1

次のリクエスト オブジェクトがあるとします。

[DataContract]
public class MyContract {
    [DataMember]
    public Guid Token { get; set; }
}

また、WCF サービス定義は次のとおりです。

[ServiceContract]
public interface IMyService {
    [OperationContract]
    bool Validate(MyContract request);
}

以下を操作に送信すると、目的の応答が得られます。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:esi="http://mynamespace.com/" xmlns:con="http://mynamespace.com">
   <soapenv:Header>
   </soapenv:Header>
   <soapenv:Body>
      <esi:Validate>
         <esi:Token>9192ef6a-819f-4a8a-8fde-4125999e33dc</esi:Token>
      </esi:Validate>
   </soapenv:Body>
</soapenv:Envelope>

無効な Guid を送信すると (これはどのタイプでも発生します)、次の応答が返されます。

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body>
      <s:Fault>
         <faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</faultcode>
         <faultstring xml:lang="en-GB">The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the &lt;serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.</faultstring>
      </s:Fault>
   </s:Body>
</s:Envelope>

これは良いことですが、私のサービスがデータの何が問題なのかを正確に知っていることを考えると、消費者にとって十分な情報ではありません。

Web 構成設定で完全な例外を公開できます<serviceDebug includeExceptionDetailInFaults="true"/>が、消費者にとっては情報が多すぎます! コード レベルでエラーをカスタマイズしたいのですが、デシリアライザーに接続する方法がわかりません。カスタム SOAP エラーと FaultContract を処理する方法は知っていますが、これはより低いレベルにあるようです。着信メッセージが CLR メソッドに到達する前に、何らかの方法でインターセプトする必要がありますか? 私が気付いていないこれを行う方法はありますか?

4

2 に答える 2

2

デシリアライザーはIDispatchMessageFormatterにあります

public class MyFormatter : IDispatchMessageFormatter
{
    readonly IDispatchMessageFormatter _originalFormatter;

    public MyFormatter(IDispatchMessageFormatter originalFormatter)
    {
      _originalFormatter = originalFormatter;
    }

    public void DeserializeRequest(Message message, object[] parameters)
    {
        try
        {
            _originalFormatter.DeserializeRequest(message, parameters);
        }
        catch(Exception ex)
        {
            //throw custom fault here
        }
    }

    public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
    {
        return _originalFormatter.SerializeReply(messageVersion, parameters, result);
    }

OperationBehavior を介してこれを接続できます。

public class MyOperationBehavior : IOperationBehavior
{
    public void Validate(OperationDescription operationDescription) { }
    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        dispatchOperation.Formatter = new MyFormatter(dispatchOperation.Formatter);
    }
    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { }
    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { }

}

属性を介して OperationBehavior をサービス操作に接続します。

構成を使用する必要がある場合は、ServiceBehavior または EndpointBehavior を介してそれらをアタッチします。


IErrorHandlerを実装することで、エラーをキャッチして処理できます。

これをサービス動作にアタッチしてみてください:

public class ServiceExceptionBehaviour : BehaviorExtensionElement, IServiceBehavior, IErrorHandler
{
   //...
   //implement all required methods
   //...
}
于 2012-10-23T20:18:13.917 に答える
0

デシリアライザーによってスローされた例外(無効なGUIDをデシリアライズする場合)を、適切な詳細レベルの適切なSOAP障害に変換したいとします。IErrorHandler(http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.aspx)とFaultConverter(http:/ )の2つの拡張ポイントがあります。 /msdn.microsoft.com/en-us/library/system.servicemodel.channels.faultconverter.aspx)。彼らが実際にあなたが望むことをすることができるかどうかを頭から離れてあなたに言うことはできませんが、それが良い出発点になることを願っています。そこにある考え方は、デフォルトの障害に依存するのではなく、発生するすべての例外を調べて、それらを障害に変換する機会を得るということです。

于 2012-10-11T08:48:43.490 に答える