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:// /msdn.microsoft.com/en-us/library/system.servicemodel.channels.faultconverter.aspx)。我无法告诉你他们是否真的能够做你想做的事,但我希望这将是一个很好的起点。那里的想法是您将有机会检查出现的所有异常并将它们自己转换为故障,而不是依赖于默认故障。

于 2012-10-11T08:48:43.490 回答