【问题标题】:Managing / Modifying Deserialisation Faults / Intercepting Responses管理/修改反序列化错误/拦截响应
【发布时间】:2012-10-11 08:08:56
【问题描述】:

假设我有以下请求对象:

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

这一切都很好,但对于我的消费者来说信息还不够,考虑到我的服务确切地知道数据出了什么问题。

我可以使用&lt;serviceDebug includeExceptionDetailInFaults="true"/&gt; 网络配置设置公开完整的异常,但这对我的消费者来说信息太多了!我宁愿在代码级别自定义错误,但我不确定如何附加到反序列化器?我知道如何处理自定义 SOAP 错误和 FaultContracts,但这似乎处于较低级别 - 我需要在传入消息到达 CLR 方法之前拦截它,不知何故?有没有我不知道的方法?

【问题讨论】:

    标签: wcf soap intercept soapfault wcf-faults


    【解决方案1】:

    反序列化器位于 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 配置中实现 BehaviorExtentionElement,并将其添加到我的默认 serviceBehavior,但 MyFormatter 中的任何方法都没有被调用:|
    • ServiceBehavior 用于根据需要附加 IErrorHandler,但格式化程序附加到 OperationBehavior。您是如何将 OperationBehavior 附加到您的服务的?您可以通过在服务方法上添加属性或将其附加到端点/服务行为来做到这一点
    • 我一直在尝试通过 WCF 配置来做所有事情(添加一个 behaviorExtension 并将其添加到服务行为列表中。这是我想要通用的东西,打开和关闭,并应用于在编写新服务时。实际上我设法捕获了一些断点,但我不得不将 IServiceBehavior 和 IErrorHandler 移到实现 IOperationBehavior 的类中。BehaviorExtensionElement 现在是一个独立的类。
    • 那么你设法让它工作了吗?如果您需要更多帮助,请告诉我。也许添加你到目前为止的代码的更新部分。
    【解决方案2】:

    我假设您希望将反序列化程序抛出的异常(反序列化无效的 Guid 时)转换为具有正确详细级别的正确 SOAP 错误。我知道有两个扩展点可能对您有所帮助 - 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)。我无法告诉你他们是否真的能够做你想做的事,但我希望这将是一个很好的起点。这里的想法是您将有机会检查所有出现的异常并将它们自己转换为错误,而不是依赖默认错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-03
      • 1970-01-01
      • 2015-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多