Silverlight でのエラーの作成と処理

Silverlight Version 3 では、サービスからクライアントへのエラー状況の伝達を可能にする、Windows Communication Foundation (WCF) の SOAP エラー プログラミング モデルを利用できます。以前のバージョンの Silverlight では、サービスで発生したエラーは、HTTP 500 応答コードとして登録されるだけで、Silverlight クライアントからは、エラーの詳細な情報にアクセスできませんでした。

サービス側の例外は、一度 SOAP エラーに変換されてから Silverlight クライアントに送信されます。クライアントがそれを受け取ると、SOAP エラーが再びエラー例外へと変換されます。エラー メッセージには、標準的な一連のプロパティと、拡張可能な detail オブジェクトが含まれており、detail オブジェクトの内容はサービス側で制御されます。エラーは、detail オブジェクトの内容によって、定義済みのエラーと未定義のエラーに分けられます。

  • 宣言されていないエラーは、サービスをデバッグする場合に適しています。エラー メッセージには、例外の種類、メッセージ、スタック トレースなど、サーバー例外に関連する情報を含めることができます。

  • 宣言されたエラーは、運用環境での使用に適しています。クライアントのロジックをエラー状況に基づいて決定する必要がある場合などに使用します。エラーの種類はサービス開発者がエラー メッセージに追加する形で定義します。エラーの種類として、具体的にどのような情報を伝達するかを制御するのもサービス開発者の役割です。

エラーの種類は、サービス メタデータで公開されます。そのため、Silverlight クライアントでは、厳密な型指定に基づいてエラーの種類を処理し、それを基にロジックを構築することができます。

WCF における SOAP エラーの処理の詳細については、「コントラクトおよびサービスのエラーの指定と処理」を参照してください。

Silverlight クライアントで使用するための WCF エラーの構成

既定では、WCF サービスは、エラー メッセージを HTTP 500 応答コードで返します。ブラウザーのネットワーク スタックの制限により、Silverlight 内でこれらのメッセージの本文にアクセスすることはできず、そのままではクライアントがエラー メッセージを読み取ることはできません。

Silverlight クライアントがアクセスできる形でエラーを送信するには、WCF サービスが、エラー メッセージの送信方法を変える必要があります。その鍵となる変更点は、WCF から返されるエラー メッセージの応答コードです。HTTP 500 ではなく、HTTP 200 の応答コードでエラー メッセージを返すようにする必要があります。この変更により、Silverlight がメッセージの本文を読み取ることができるようになり、同じサービスの WCF クライアントは、引き続き通常のエラー処理手順を使用することができます。

サーバー側の変更は、Silverlight のエラーに対する WCF のエンドポイントの動作を定義することによって行います。この方法を次のコード例に示します。


public class SilverlightFaultBehavior : BehaviorExtensionElement, IEndpointBehavior
    {        
        
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            SilverlightFaultMessageInspector inspector = new SilverlightFaultMessageInspector();
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
        }

        public class SilverlightFaultMessageInspector : IDispatchMessageInspector
        {
            
            public void BeforeSendReply(ref Message reply, object correlationState)
            {
                if (reply.IsFault)
                {
                    HttpResponseMessageProperty property = new HttpResponseMessageProperty();

                    // Here the response code is changed to 200.
                    property.StatusCode = System.Net.HttpStatusCode.OK;


                    reply.Properties[HttpResponseMessageProperty.Name] = property;
                }
            }
            
            public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
            {
                // Do nothing to the incoming message.
                return null;
            }


        }

        // The following methods are stubs and not relevant. 

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }


        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public override System.Type BehaviorType
        {
            get { return typeof(SilverlightFaultBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new SilverlightFaultBehavior();
        }

    }

ここに示した WCF エンドポイント動作のコードは、WCF サービス構成ファイル内のサービスに対して構成されている必要があります。必要な変更を次のコード例に示します。わかりやすくするために、一部のセクションは省略されています。


<system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name=”silverlightFaults” 
             type=”Microsoft.Silverlight.Samples.SilverlightFaultBehavior, 
             SilverlightFaultBehavior, 
             Version=1.0.0.0, 
             Culture=neutral, 
             PublicKeyToken=null”/>
      </behaviorExtensions>
    </extensions>
    <behaviors>
        <endpointBehaviors>
          <behavior name=”SilverlightFaultBehavior”>
            <silverlightFaults/>
          </behavior>
        </endpointBehaviors>
    </behaviors>
    <services>
        <service name=”Calculator.Web.Service”>
            <endpoint address=”” 
                      binding=”basicHttpBinding” 
                      contract=”Calculator.Web.Service” 
                      behaviorConfiguration=”SilverlightFaultBehavior” />
</service>
  </services>
</system.serviceModel> 

この変更を WCF サービスに反映すると、このサービスにアクセスした Silverlight クライアントがエラーにアクセスできるようになります。

宣言されていないエラーの使用 (デバッグ向け)

送信できる SOAP エラーには、宣言された SOAP エラーと宣言されていない SOAP エラーの 2 種類があります。宣言された SOAP エラーは、操作として、カスタム SOAP エラーの種類を指定する FaultContractAttribute 属性を持つエラーです。これらの SOAP エラーは運用環境で使用されます。この点については、次のセクションで説明します。宣言されていない SOAP エラーは、操作のコントラクトに指定されていないエラーです。これらの SOAP エラーはデバッグ目的でのみ使用されます。このセクションでは、宣言されていない SOAP エラーについて説明します。

宣言されていない SOAP エラーは、サービスをデバッグする場合に適しています。こうした未定義のエラーは、簡単な設定で、サービスからクライアントに送信されるエラー メッセージに例外についての完全な情報を格納して伝達することができます。具体的には、<serviceDebug> 構成要素の includeExceptionDetailInFaults 属性を true に設定します。

<serviceDebug includeExceptionDetailInFaults="true"/>

Silverlight クライアント コードでは、このエラーを Web サービスの操作の応答コールバック内で処理できます。


void proxy_CalculateCompleted(object sender, CalculateCompletedEventArgs e)
{
    if (e.Error == null)
    {
        // In case of success
    }
    else if (e.Error is FaultException<ExceptionDetail>)
    {
        FaultException<ExceptionDetail> fault = e.Error as FaultException<ExceptionDetail>;

         // fault.Detail.Type contains the server exception type.
         // fault.Detail.Message contains the server exception message.
         // fault.Detail.StackTrace contains the server stack trace.
         
    }
}

Dd470096.note(ja-jp,VS.95).gifメモ :
この WCF 構成は、運用環境には展開しないでください。理由は、例外の種類やスタック トレースなど、慎重な扱いが要求されるサーバー側のデータが公開され、セキュリティ上のリスクが伴うためです。

定義済みのエラーを使ったロジックの構築

運用環境でエラーを使用するには、WCF サービスでエラーの種類を定義する必要があります。エラーの種類として格納できるのは、公開しても安全な情報だけです。たとえば、算術演算のサービスでは、次のようなエラーの種類を定義できます。


public enum Operation
{
    Add,
    Subtract,
    Multiply,
    Divide
}

public class ArithmeticFault
{
    public Operation Operation { get; set; }
    public string Description { get; set; }
}

エラーの発生が予想される操作は、System.ServiceModel.FaultContractAttribute 属性でマークする必要があります。これにより、対応する型が、WCF によってサービス メタデータに公開されます。


[OperationContract]
[FaultContract(typeof(ArithmeticFault))]
public int Calculate(Operation op, int a, int b)
{
    // ...
}

System.ServiceModel.FaultException<T> クラスは、エラーをネットワークを介して送信するために使用されます。


ArithmeticFault fault = new ArithmeticFault();
fault.Operation = Operation.Divide;
fault.Description = "Cannot divide by zero.";
throw new FaultException<ArithmeticFault>(fault);

Silverlight 用に、この WCF サービスのプロキシを生成した場合、ArithmeticFault クラスのコードが Visual Studio 2008 によって生成されます (サービス メタデータで公開されているため)。これにより、このクラスを Silverlight クライアントの内部で使用し、プログラミング ロジック駆動できます。


void proxy_CalculateCompleted(object sender, CalculateCompletedEventArgs e)
{
    if (e.Error == null)
    {
        // In case of success
    }
    else if (e.Error is FaultException<ArithmeticFault>)
    {
        FaultException<ArithmeticFault> fault = e.Error as FaultException<ArithmeticFault>;

        // fault.Detail.Operation as defined on the service
        // fault.Detail.Description as defined on the service

    }
}

関連項目

このトピックに関するコメントを Microsoft に送信する。

Copyright© 2009 by Microsoft Corporation. All rights reserved.
表示: