Wcf 管理/修改反序列化故障/拦截响应

Wcf 管理/修改反序列化故障/拦截响应,wcf,soap,intercept,soapfault,wcf-faults,Wcf,Soap,Intercept,Soapfault,Wcf Faults,假设我有以下请求对象: [DataContract] public class MyContract { [DataMember] public Guid Token { get; set; } } 以及WCF服务定义,如下所示: [ServiceContract] public interface IMyService { [OperationContract] bool Validate(MyContract request); } 如果我将以下内容发送到

假设我有以下请求对象:

[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>
<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>

9192ef6a-819f-4a8a-8fde-4125999e33dc
如果发送的Guid无效(任何类型都会发生这种情况),则会得到以下响应:

<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>
<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>

a:内部故障
由于内部错误,服务器无法处理该请求。有关错误的更多信息,请在服务器上启用IncludeExceptionDetailInFaults(从ServiceBehaviorAttribute或从serviceDebug>configuration behavior),以便将异常信息发送回客户端,或者根据Microsoft.NET Framework SDK文档打开跟踪,并检查服务器跟踪日志。
这一切都很好,但对于我的消费者来说,信息还不够,因为我的服务知道数据到底出了什么问题


我可以使用
web配置设置公开完整的异常,但这对我的消费者来说太多了!我更愿意在代码级别自定义错误,但我不确定如何连接到反序列化程序?我知道如何处理自定义SOAP错误和FaultContract,但这似乎是在一个较低的级别上-不知何故,我需要在传入消息到达CLR方法之前拦截它?是否有一种我不知道的方法可以做到这一点?

我假设您希望将反序列化程序(在反序列化无效Guid时)引发的异常转换为具有正确详细级别的正确SOAP错误。据我所知,有两个扩展点可能会对您有所帮助—IErrorHandler()和FaultConverter()。我不能马上告诉你他们是否真的能做你想做的事,但我希望这将是一个很好的起点。这里的想法是,您将有机会检查出现的所有异常并自己将其转换为故障,而不是依赖默认故障。

反序列化器位于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
   //...
}

这就可以解释了——我正在查看IClientMessageInspector、IDispatchMessageInspector,但没有找到任何东西。我将尽快对此进行尝试:)努力让它实际捕获任何东西-在web配置中实现BehaviorExtensionElement,并将其添加到我的默认serviceBehavior中,但MyFormatter中的任何方法都没有被调用:| serviceBehavior用于附加IErrorHandler(如果需要),但是格式化程序附加到OperationBehavior。您是如何将OperationBehavior附加到您的服务的?您可以通过在您的服务方法上添加一个属性,或者将其附加到端点/服务行为来实现这一点。我们一直在尝试通过WCF配置完成所有工作(添加behaviorExtension并将其添加到服务行为列表中。我希望在编写新服务时将其设置为泛型、打开和关闭,并应用到新服务中。我实际上设法捕获了一些断点,但我必须将IServiceBehavior和IErrorHandler移动到实现IOperationBehavior.BehaviorExtensionEle的类中ment现在是一个独立的类。那么您是否设法让它工作了?如果您需要更多帮助,请告诉我。也许可以添加到目前为止您拥有的代码的更新部分。