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

时间:2012-10-11 08:08:56

标签: 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);
}

如果我将以下内容发送给操作,我会收到所需的回复:

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

考虑到我的服务确切地知道数据有什么问题,这对我的消费者来说是好的,但不是真的足够的信息。

我可以使用<serviceDebug includeExceptionDetailInFaults="true"/>网络配置设置公开完整的例外,但这对我的消费者来说太多了!我宁愿在代码级别自定义错误,但我不确定如何附加到反序列化程序?我知道如何处理自定义SOAP故障和FaultContracts,但这似乎是在较低的水平 - 我需要在它到达CLR方法之前拦截传入的消息,不知何故?有没有办法做到这一点,我不知道?

2 个答案:

答案 0 :(得分: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
   //...
}

答案 1 :(得分:0)

我假设您希望将反序列化器抛出的异常(在反序列化无效Guid时)转换为具有正确详细程度的正确SOAP Fault。我知道有两个可扩展点可以帮到你 - IErrorHandler(http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.aspx)和FaultConverter(http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.faultconverter.aspx)。不能告诉你他们是否真的能够做你想做的事情,但我希望这将是一个很好的起点。我们的想法是,您将有机会检查出现的所有异常,并将其自身转换为故障,而不是依赖于默认故障。