次の方法で共有


エラーの送受信

SOAP エラーは、サービスからクライアントにエラー状態情報を伝達し、双方向の場合はクライアントからサービスに相互運用可能な方法で伝えます。 通常、サービスはカスタム 障害コンテンツを定義し、それらを返すことができる操作を指定します。 (詳細については、「 障害の定義と指定」を参照してください)。このトピックでは、対応するエラー状態が発生したときにサービスまたは双方向クライアントがこれらのエラーを送信する方法と、クライアントまたはサービス アプリケーションがこれらのエラーを処理する方法について説明します。 Windows Communication Foundation (WCF) アプリケーションでのエラー処理の概要については、「 コントラクトとサービスでのエラーの指定と処理」を参照してください。

SOAP エラーの送信

宣言された SOAP エラーは、操作にカスタム SOAP エラーの種類を指定する System.ServiceModel.FaultContractAttribute があるエラーです。 宣言されていない SOAP エラーは、操作のコントラクトで指定されていないエラーです。

宣言された障害を送信する

宣言された SOAP エラーを送信するには、SOAP エラーに該当するエラー状態を検出し、新しい System.ServiceModel.FaultException<TDetail> をスローします。この場合、型パラメーターは、その操作の FaultContractAttribute に指定されている型の新しいオブジェクトです。 次のコード例は、FaultContractAttribute を使用して、SampleMethod 操作が GreetingFault の詳細を持つ SOAP フォールトを返すことができることを指定する方法を示しています。

[OperationContract]
[FaultContractAttribute(
  typeof(GreetingFault),
  Action="http://www.contoso.com/GreetingFault",
  ProtectionLevel=ProtectionLevel.EncryptAndSign
  )]
string SampleMethod(string msg);
<OperationContract, FaultContractAttribute(GetType(GreetingFault), Action:="http://www.contoso.com/GreetingFault", ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
Function SampleMethod(ByVal msg As String) As String

GreetingFaultエラー情報をクライアントに伝達するには、次のコード例のように、適切なエラー状態をキャッチし、新しいSystem.ServiceModel.FaultException<TDetail> オブジェクトを引数としてGreetingFault型の新しいGreetingFaultをスローします。 クライアントが WCF クライアント アプリケーションの場合、型がSystem.ServiceModel.FaultException<TDetail>型のGreetingFaultマネージド例外として発生します。

throw new FaultException<GreetingFault>(new GreetingFault("A Greeting error occurred. You said: " + msg));
    Throw New FaultException(Of GreetingFault)(New GreetingFault("A Greeting error occurred. You said: " & msg))
End If

宣言されていないエラーの送信

宣言されていないエラーを送信すると、WCF アプリケーションの問題をすばやく診断してデバッグするのに非常に便利ですが、デバッグ ツールとしての有用性は限られています。 より一般的には、デバッグ時には、 ServiceDebugBehavior.IncludeExceptionDetailInFaults プロパティを使用することをお勧めします。 この値を true に設定すると、FaultException<TDetail>ExceptionDetail型の例外などのエラーが発生します。

Von Bedeutung

マネージド例外は内部アプリケーション情報を公開できるため、 ServiceBehaviorAttribute.IncludeExceptionDetailInFaults または ServiceDebugBehavior.IncludeExceptionDetailInFaultstrue に設定すると、WCF クライアントは、個人を特定できるその他の機密情報など、内部サービス操作の例外に関する情報を取得できます。

そのため、 ServiceBehaviorAttribute.IncludeExceptionDetailInFaults または ServiceDebugBehavior.IncludeExceptionDetailInFaultstrue に設定することは、サービス アプリケーションを一時的にデバッグする方法としてのみ推奨されます。 さらに、この方法でハンドルされないマネージド例外を返すメソッドの WSDL には、FaultException<TDetail>型のExceptionDetailのコントラクトは含まれません。 クライアントは、デバッグ情報を正しく取得するために、不明な SOAP エラー ( System.ServiceModel.FaultException オブジェクトとして WCF クライアントに返される) の可能性を想定する必要があります。

宣言されていない SOAP エラーを送信するには、 System.ServiceModel.FaultException オブジェクト (つまり、ジェネリック型 FaultException<TDetail>ではなく) をスローし、文字列をコンストラクターに渡します。 これは、スローされたSystem.ServiceModel.FaultException例外として WCF クライアント アプリケーションに公開されており、文字列はFaultException<TDetail>.ToStringメソッドを呼び出すことによって取得できます。

文字列型の SOAP フォルトを宣言し、サービス内でFaultException<TDetail>としてこれをスローした場合、型パラメーターSystem.Stringの文字列値はFaultException<TDetail>.Detailプロパティに割り当てられ、FaultException<TDetail>.ToStringからは利用できません。

障害の処理

WCF クライアントでは、クライアント アプリケーションに関係する通信中に発生する SOAP エラーは、マネージド例外として発生します。 プログラムの実行中に発生する可能性のある例外は多数ありますが、WCF クライアント プログラミング モデルを使用するアプリケーションでは、通信の結果として次の 2 つの型の例外を処理することが期待できます。

TimeoutException オブジェクトは、操作が指定されたタイムアウト期間を超えるとスローされます。

CommunicationException オブジェクトは、サービスまたはクライアントに回復可能な通信エラー状態がある場合にスローされます。

CommunicationException クラスには、FaultExceptionとジェネリック FaultException<TDetail>型の 2 つの重要な派生型があります。

FaultException 例外は、リスナーが予期しないエラーまたは操作コントラクトで指定されたエラーを受け取ったときにスローされます。通常、これは、アプリケーションがデバッグ中で、サービスに ServiceDebugBehavior.IncludeExceptionDetailInFaults プロパティが true に設定されている場合に発生します。

FaultException<TDetail> 例外は、操作コントラクト内に指定されたエラーが、双方向操作 (つまり、OperationContractAttributeIsOneWay が設定されている false 属性を持つメソッド) への応答で受信された場合に、クライアントでスローされます。

WCF サービスで ServiceBehaviorAttribute.IncludeExceptionDetailInFaults または ServiceDebugBehavior.IncludeExceptionDetailInFaults プロパティが true に設定されているとき、クライアントはこれを、型 FaultException<TDetail> の宣言されていない ExceptionDetail として体験します。 クライアントは、この特定の障害をキャッチするか、 FaultExceptionの catch ブロックでエラーを処理できます。

通常、クライアントとサービスには、 FaultException<TDetail>TimeoutExceptionCommunicationException の例外のみが対象です。

もちろん、他の例外も発生します。 予期しない例外には、 System.OutOfMemoryExceptionなどの致命的なエラーが含まれます。通常、アプリケーションではこのようなメソッドをキャッチしないでください。

エラー例外を正しい順序でキャッチする

FaultException<TDetail>FaultExceptionから派生し、FaultExceptionCommunicationExceptionから派生するため、これらの例外を適切な順序でキャッチすることが重要です。 たとえば、最初に CommunicationExceptionをキャッチする try/catch ブロックがある場合、指定されたすべての SOAP エラーと指定されていない SOAP エラーがそこで処理されます。カスタム FaultException<TDetail> 例外を処理する後続の catch ブロックは呼び出されません。

1 回の操作で、指定したエラーの数をいくつでも返すことができることに注意してください。 各障害は一意の型であり、個別に処理する必要があります。

チャネルを閉じるときに例外を処理する

前述の説明のほとんどは、アプリケーション メッセージの処理中に送信されたエラー、つまり、クライアント アプリケーションが WCF クライアント オブジェクトに対する操作を呼び出すときにクライアントによって明示的に送信されるメッセージと関係があります。

ローカルオブジェクトがあっても、オブジェクトを破棄することにより、リサイクルプロセス中に発生する例外を発生させたり、隠したりすることができます。 WCF クライアント オブジェクトを使用すると、同様のことが発生する可能性があります。 操作を呼び出すときは、確立された接続経由でメッセージを送信します。 また、チャネルを閉じると、すべての操作が正常に返されたとしても、接続を完全に閉じることができなかったり、接続が既に閉じたりしている場合には、例外がスローされる可能性があります。

通常、クライアント オブジェクト チャネルは次のいずれかの方法で閉じられます。

  • WCF クライアント オブジェクトがリサイクルされるとき。

  • クライアント アプリケーションが ClientBase<TChannel>.Closeを呼び出すとき。

  • クライアント アプリケーションが ICommunicationObject.Closeを呼び出すとき。

  • クライアント アプリケーションが、セッションの終了操作である操作を呼び出す場合。

いずれの場合も、チャネルを閉じると、アプリケーション レベルで複雑な機能をサポートするためにメッセージを送信している可能性がある基になるチャネルをチャネルが閉じ始めるよう指示されます。 たとえば、コントラクトでセッションが必要な場合、バインディングはセッションが確立されるまでサービス チャネルとメッセージを交換してセッションを確立しようとします。 チャネルが閉じられると、基になるセッション チャネルは、セッションが終了したことをサービスに通知します。 この場合、チャネルが既に中止、閉じている、または使用できない場合 (ネットワーク ケーブルが取り外されている場合など)、クライアント チャネルはセッションが終了したことをサービス チャネルに通知できず、例外が発生する可能性があります。

必要に応じてチャネルを中止する

チャネルを閉じると例外がスローされる可能性があるため、正しい順序でエラー状態をキャッチするだけでなく、呼び出しに使用されたチャネルを catch ブロックで中止することが重要です。

エラーが操作に固有のエラー情報を伝達し、他のユーザーが操作を使用できる可能性がある場合は、チャネルを中止する必要はありません (このようなケースはまれです)。 それ以外の場合は、チャネルを中止することをお勧めします。 これらのすべての点を示すサンプルについては、「 予期される例外」を参照してください。

次のコード例は、宣言されたエラーや宣言されていないエラーなど、基本的なクライアント アプリケーションで SOAP エラー例外を処理する方法を示しています。

このサンプル コードでは、 using コンストラクトは使用しません。 チャネルを閉じると例外がスローされる可能性があるため、アプリケーションではまず WCF クライアントを作成し、その後、同じ try ブロック内でクライアントを開いて使用し、閉じることが推奨されます。 詳細については、「 WCF クライアントの概要 」および「 Close and Abort を使用して WCF クライアント リソースを解放する」を参照してください。

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.WCF.Documentation;

public class Client
{
  public static void Main()
  {
    // Picks up configuration from the config file.
    SampleServiceClient wcfClient = new SampleServiceClient();
    try
    {
      // Making calls.
      Console.WriteLine("Enter the greeting to send: ");
      string greeting = Console.ReadLine();
      Console.WriteLine("The service responded: " + wcfClient.SampleMethod(greeting));

      Console.WriteLine("Press ENTER to exit:");
      Console.ReadLine();

      // Done with service.
      wcfClient.Close();
      Console.WriteLine("Done!");
    }
    catch (TimeoutException timeProblem)
    {
      Console.WriteLine("The service operation timed out. " + timeProblem.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException<GreetingFault> greetingFault)
    {
      Console.WriteLine(greetingFault.Detail.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException unknownFault)
    {
      Console.WriteLine("An unknown exception was received. " + unknownFault.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (CommunicationException commProblem)
    {
      Console.WriteLine("There was a communication problem. " + commProblem.Message + commProblem.StackTrace);
      Console.ReadLine();
      wcfClient.Abort();
    }
  }
}

Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports Microsoft.WCF.Documentation

Public Class Client
    Public Shared Sub Main()
        ' Picks up configuration from the config file.
        Dim wcfClient As New SampleServiceClient()
        Try
            ' Making calls.
            Console.WriteLine("Enter the greeting to send: ")
            Dim greeting As String = Console.ReadLine()
            Console.WriteLine("The service responded: " & wcfClient.SampleMethod(greeting))

            Console.WriteLine("Press ENTER to exit:")
            Console.ReadLine()

            ' Done with service. 
            wcfClient.Close()
            Console.WriteLine("Done!")
        Catch timeProblem As TimeoutException
            Console.WriteLine("The service operation timed out. " & timeProblem.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch greetingFault As FaultException(Of GreetingFault)
            Console.WriteLine(greetingFault.Detail.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch unknownFault As FaultException
            Console.WriteLine("An unknown exception was received. " & unknownFault.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch commProblem As CommunicationException
            Console.WriteLine("There was a communication problem. " & commProblem.Message + commProblem.StackTrace)
            Console.ReadLine()
            wcfClient.Abort()
        End Try
    End Sub
End Class

こちらも参照ください