WCF IErrorHandler 将 FaultException 返回给 SOAP,将 WebHttpException 返回给 POX 和 Json 端点

Posted

技术标签:

【中文标题】WCF IErrorHandler 将 FaultException 返回给 SOAP,将 WebHttpException 返回给 POX 和 Json 端点【英文标题】:WCF IErrorHandler to return FaultException to SOAP and WebHttpException to POX and Json endpoints 【发布时间】:2011-11-03 13:10:55 【问题描述】:

我有一组使用 IErrorHandler 包装异常的 SOAP Web 服务,具体来说:

public sealed class ErrorHandler : IErrorHandler

    public bool HandleError(Exception error)
    
        return true;
    

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    
        // don't wrap existing fault exceptions
        if ((error is FaultException)) return;

        // our basic service fault
        var businessFault = new BusinessFault  FaultMessage = error.Message, FaultReference = "Internal" ;

        // Resource based faultReason
        var faultReason = new FaultReason(Properties.Resources.BusinessFaultReason);
        var faultcode = FaultCodeFactory.CreateVersionAwareSenderFaultCode(InternalFaultCodes.BusinessFailure.ToString(), Service.Namespace);

        var faultException = new FaultException<BusinessFault>(
            businessFault,
            faultReason,
            faultcode);

        // Create message fault
        var messageFault = faultException.CreateMessageFault();

        // Create message using Message Factory method
        fault = Message.CreateMessage(version, messageFault, faultException.Action);
    

我现在为 Json 和 Pox 添加了额外的端点,它们可以正常工作,除非发生异常。对于 Json 端点,FaultException 以 XML 形式返回。

我从其他 SO 帖子中了解到,对于 REST,我最好抛出 WebHttpException:

throw new WebFaultException<BusinessFault>(detail, HttpStatusCode.BadRequest);

或者覆盖 ProvideFault 中的响应消息属性,因此:

var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);
fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);

var rmp = new HttpResponseMessageProperty

    StatusCode = System.Net.HttpStatusCode.BadRequest,
    StatusDescription = "See fault object for more information."
;
fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);

不过,MSDN 对WebHttpException 有一些有趣的评论,即:

当使用 WCF REST 端点(WebHttpBinding 和 WebHttpBehavior 或 WebScriptEnablingBehavior) 响应上的 HTTP 状态码已设置 因此。但是,WebFaultException 可以与非 RE​​ST 一起使用 端点和行为类似于常规的 FaultException。

当使用 WCF REST 端点时,序列化的响应格式 故障的确定方式与非故障响应相同。更多 有关 WCF REST 格式的信息,请参阅 WCF REST 格式。

因此建议我需要转换当前的 ProvideFault 方法以提供新的 WebHttpException(包装任何现有的异常或故障异常),然后 SOAP 仍然可以正常工作。

有没有人想试一试那会是什么样子(.Net4.0 btw)?我想要一个错误处理程序来统治它们!

【问题讨论】:

我不明白你的问题。您想为 JSON/POX/SOAP 端点单独实现 IErrorHandler 吗? @Cyber​​maxs 正确。 WCF 允许您向不同类型的客户端公开多个端点。这一切都很好,直到你需要提出错误。如果我(通常)提出 SOAP 错误,那么 HTTP 客户端将不会更明智。如果我提出 HTTP 错误,那么 SOAP 客户端就会被蒙在鼓里。 【参考方案1】:

我的印象是,使用 webHttpBinding 是一种获得 JSON/POX/SOAP 的“一体化”功能的方法,而不是为每个使用单独的绑定(即 wsHttpBindingbasicHttpBinding等等。)。那么,您难道不能直接抛出 WebHttpException,然后让它为您提供所需的所有错误详细信息,而不管技术如何?

【讨论】:

【参考方案2】:

在我正在处理的 REST 应用程序中,我创建了一个派生自 WebFaultException&lt;T&gt; 的新类,该类将一些附加数据附加到捕获的服务异常。在派生类的实例上调用CreatingMessageFault() 方法让我从错误处理程序的ProvideFault() 方法返回我选择的异常数据作为SOAP 错误,让WCF 确定正确的消息格式。

我正在使用webHttpBinding 绑定除部分第三方服务之外的所有服务。

编辑:添加代码示例

public class ErrorHandler : IErrorHandler, IServiceBehavior
       
    public virtual void ProvideFault( Exception error, MessageVersion version, ref Message fault )
    
        // Include next level of detail in message, if any.
        MyFaultException myFaultException =
            ((error is MyFaultException) &&
                ((MyFaultException)error).Detail != null)
            ? new MyFaultException(error.Message + " - " +
                    ((MyFaultException)error).Detail.Message, error)
            : new MyFaultException( error.Message, error );
        MessageFault messageFault = myFaultException.CreateMessageFault();
        fault = Message.CreateMessage( version, messageFault, myFaultException.Action );
    

/// <summary>
/// Class used to return exception data from my WCF services.
/// </summary>
/// <remarks>
/// This class is used by a web service to pass exception data back and a
/// data object to the client. This class inherits WebFaultException, which
/// is handled specially by the WCF WebServiceHost2 service class and
/// generates a WebException on the client.
/// </remarks>
public class MyFaultException : WebFaultException<BusinessFault>

public class MyFaultException : WebFaultException<BusinessFault>

    public MyFaultException(string message)
        : this(HttpStatusCode.BadRequest, message)  

    public MyFaultException(HttpStatusCode statusCode, string message)
        : base(new BusinessFault(message), statusCode)  

然后在您的服务中,您可以抛出异常以将故障数据传递给您的客户端:

        try
        
            // Successful operation proceeds normally.
        
        catch (ApplicationException e)
        
            // Failure generates MyFaultException.
            throw new MyFaultException("Operation failed with " + e.Message);
        

【讨论】:

如果您想添加代码示例,我可以尝试您所描述的内容。 我会试着找点时间试试看。那么,我会很高兴地为您提供答案。不过可能需要一段时间,因为我已经有一段时间没有从事这个项目了!

以上是关于WCF IErrorHandler 将 FaultException 返回给 SOAP,将 WebHttpException 返回给 POX 和 Json 端点的主要内容,如果未能解决你的问题,请参考以下文章

使用 HandleError 或 ProvideFault 中的 IErrorHandler 在 WCF 中记录异常?

WCF错误处理:一刀切——IErrorHandler

WCF自定义错误处理(IErrorHandler接口的用法)

WCF错误协定声明

服务边界处的 WCF 错误日志记录

IErrorHandler