4

そのため、WCF サービスで Enterprise Library を使用して、例外関連の作業をいくつか実行しようとしています。

私の考えは、「NullReferenceException」などの「カスタム例外ハンドラー」を設定し、「カスタム例外ハンドラー」で FaultException 例外を作成することです。

私の理解では、この「新しい」例外はネットワークを通過し、クライアントでキャッチします。

理解を深めるためのコード:

WCF サービス:

[ServiceContract(Name="MyService", ConfigurationName="MyNamespace.MyService")]
    [ExceptionShielding("PolicyName")]
    public interface IMyService
    {
        [OperationContract]
        [FaultContract(typeof(MyFaultContract))]
        string Method(String Param);
}

public class MyService : IMyService
    {
        public string Method(String Param)
        {
          throw new  NullReferenceException("code-created null message here");
        }
}

カスタム例外ハンドラ: (エンタープライズ ライブラリ)

public class MyExceptionHandler : IExceptionHandler
    {
        public MyExceptionHandler(NameValueCollection collection) { }

        public MyExceptionHandler() { }

        public System.Exception HandleException(System.Exception exception, 
                              Guid handlingInstanceId)
        {
                MyFaultContract details = new MyFaultContract();
                if (exception is NullReferenceException)
                {
                    details.ErrorCode = MyFaultCode.NullReferenceException;
                    details.OriginalMessage = exception.Message;
                    details.MyMessage = "Null Reference exception here!";
                }
                return new FaultException<MyFaultContract>(details);
            }
}

NullReferenceException を「カスタム例外ハンドラー」にマップするアプリ構成ファイル:

<exceptionPolicies>
      <add name="PolicyName">
        <exceptionTypes>
          <add name="NullReferenceException" type="System.NullReferenceException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
            postHandlingAction="ThrowNewException">
            <exceptionHandlers>
              <add type="MyExceptionHandler, MyApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                name="MyExceptionHandler" />
            </exceptionHandlers>
          </add>
        </exceptionTypes>
      </add>
    </exceptionPolicies>

そして最後に、この FaultException をキャッチすることを期待するクライアント コード:

MyService.MyServiceClient client = new MyService.MyServiceClient();
            client.Open();
            try
            {
                string result = client.Method(string parameter);
            }

            catch (System.ServiceModel.FaultException<MyService.MyFaultContract> ex)
            {
                // where I think exception should end up
            }
            catch (System.ServiceModel.FaultException ex)
            {
                // general FaultException
            }

しかし、代わりに、応答アクションが必要であることを示す ProtocolException が発生します。

アクション '' の操作 'メソッド' に対する応答メッセージを受信しました。ただし、クライアント コードにはアクション 'http://tempuri.org/MyService/MethodResponse' が必要です。

私は何を間違っていますか?「カスタム例外ハンドラー」でカスタム FaultContract を使用して FaultException を返す (明示的にスローしない) ことは可能ですか?

アドバイスをいただければ幸いです。

更新: ご覧のとおり、「カスタム例外ハンドラー」の処理後のアクションは「ThrowNewException」に設定されています。「NotifyRethrow」に変更すると、「ProtocolException」が発生しなくなります。代わりに、クライアントは通常の "FaultException" (カスタム型ではない) をキャッチします。

ここで問題となるのは、元のカスタム型の FaultException がネットワークを通過しない理由です。

Update 2 忘れていたことの 1 つは、WCF サービスが IIS ではなく ServiceHost 内で実行されていることです。したがって、基本的には、ServiceHost を作成し、この ServiceHost を介して Service1 インターフェイスを公開する Windows サービスがあります。

これがこの問題と関係があると私が考える理由は、Enterprise Library が、サービス境界内だけでなく、アプリケーション全体で例外を処理すると主張しているためです。これにより、例外のスローが遅すぎる可能性がありますか? それとも適切なレベルではありませんか?

更新 3
投稿ありがとうございます。そうです、私がカスタム ハンドラーをいじっている唯一の理由は、MyFaultCode 値を設定したいからです。私はあなたのアドバイスを試しました-2つのハンドラーを構成しました。

最初はカスタム ハンドラーで、NullReference 例外をキャッチします。次に、MyFaultContract フィールドを使用して、新しい例外 - MyApplicationException をスローします。

次に、2 番目のハンドラーを構成しました。組み込みの "Fault Contract Exception Handler" は、MyApplicationException をキャッチし、新しい FaultException を作成し、MyFaultcontract を MyApplicationException から新しく作成された FaultException に自動的にマップします。

WCF クライアントは、カスタム コントラクトではなく、一般的な FaultException を引き続きキャッチします。

4

2 に答える 2

3

カスタム WCF IErrorHandler実装の使用を検討します。サービス メソッド内で発生するすべての未処理の例外を一元的に処理する場所を提供します。

私の意見では、Ent Lib を使用するよりもクリーンになり、依存関係が 1 つ少なくなり、構成でそのエラー マッピングが必要ないため、XML が少なくなります。

例:

public class MyServiceErrorHandler : IErrorHandler
{
    /// <summary>
    /// Central error handling for WCF services.
    /// Whenever a service encounteres an unhandled exception, it will end up here.
    /// This method will log the error and continue with normal error processing.
    /// </summary>
    /// <param name="error">The unhandled exception thrown from a service method.</param>
    /// <returns>true if the exceptions has been handled, false if normal error processing should continue. This implementation will always return false.</returns>
    public virtual bool HandleError(Exception error)
    {
        return false; // returning false so that WCF will still process the exception as usual.
    }

    /// <summary>
    /// Create a custom Fault message to return to the client.
    /// </summary>
    /// <param name="error">The Exception object thrown in the course of the service operation.</param>
    /// <param name="version">The SOAP version of the message.</param>
    /// <param name="fault">The Message object that is returned to the client, or service, in the duplex case.</param>
    public virtual void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        //If it's a FaultException already, then we have nothing to do
        if (error is FaultException)
            return;

        // pack the exception info into the Fault Contract
        MyFaultContract details = new MyFaultContract();
        if (exception is NullReferenceException)
        {
            details.ErrorCode = MyFaultCode.NullReferenceException;
            details.OriginalMessage = error.Message;
            details.MyMessage = "Null Reference exception here!";
        }
        var faultException = new FaultException<MyFaultContract>(details);

        // turn the fault contract into the response WCF Message.
        var messageFault = faultException.CreateMessageFault();
        fault = Message.CreateMessage(version, messageFault, faultException.Action);
    }
}

もちろん、Ent Lib を使用する他の理由がある場合は、先に進んでください。どうにかして両者を結びつけることができます。

このリンクには、カスタム IErrorHandler 動作の追加など、エラー処理に関する良い読み物もあります: http://www.codeproject.com/KB/WCF/WCFErrorHandling.aspx

于 2012-01-06T21:31:17.377 に答える
0

コメントしようと思ったのですが、長くなってしまいました。

The Fault Contract Exception Handler で Exception Handling Block Exception Shielding を使用することを検討しましたか? 私はそれがあなたが望むほとんどのことをすると思います。 http://msdn.microsoft.com/en-us/library/ff953192(v=PandP.50).aspx

アプローチは、独自のハンドラーを作成して、すべてのプロパティをカスタムの例外の種類にマップすることです。次に、FaultContractExceptionHandler を構成して、例外のプロパティを障害コントラクトのプロパティにマップします。

MyFaultCode の値を設定する必要がなければ、おそらくカスタム ハンドラーをまとめて作成することを避けることができます。

于 2012-01-08T21:56:53.923 に答える