【问题标题】:WCF REST Services - Generic exception handlingWCF REST 服务 - 通用异常处理
【发布时间】:2010-12-16 13:34:08
【问题描述】:

我有很多遗留代码现在是 WCF REST 服务的后端 - 如果这很重要的话,它以前曾经是普通的 WCF 服务后端。我想实现一种机制,可以捕获任何方法中的任何异常并对其进行分析。如果结果是已知错误,则会被处理并变成一个友好的错误。

我知道我可以抛出 FaultExceptionWebProtocolException 而不是“通常”的异常,但是有很多地方会在整个代码中抛出异常,并且查找所有异常是一个非常痛苦的选择。

我尝试添加一个端点行为扩展来创建一个新的行为,该行为覆盖标准WebHttpBehavior.AddServerErrorHandlers 方法并将我的错误处理程序(IErrorHandler 实现)添加到端点调度程序错误处理程序集合中。在错误处理程序中,我分析异常并基于此异常创建(或不创建)所需的故障。

我希望这种机制能够为任何已知异常返回自定义数据,但我错了。老微软已经实现了一个美妙的不可避免的WebHttpBehavior2,它无条件地将一个内部Microsoft.ServiceModel.Web.WebErrorHandler 添加到端点调度程序错误处理程序集合的末尾。此处理程序忽略所有先前执行的处理程序,只识别一小部分异常,而大多数异常被解释为“内部服务器错误”,仅此而已。

问题是我是否走在正确的道路上,是否有办法在 WCF REST 机制中禁用此处理程序,或者使用新异常引入它(例如,当任何异常被捕获时,它首先由我的处理程序处理如果它们抛出/返回,例如,FaultException,那么这个新异常将提供给Microsoft.ServiceModel.Web.WebErrorHandler,而不是原来的)。如果我对IErrorHandler 和行为扩展的所有实验都毫无价值,那么还有什么替代方案?再说一次,我真的不想修改异常抛出逻辑,我想要一个地方来捕获异常并处理它们。

非常感谢!

【问题讨论】:

    标签: .net wcf rest


    【解决方案1】:

    当您将 WCF SOAP 服务更改为 REST 时,错误报告和处理的整个心态都会发生变化。

    在 SOAP 中,错误是合同的一部分。在 REST 中,它们只是成为您在 HTTP 响应代码和描述中输出的代码。

    这里有一个 catch sn-p:

    catch (Exception e)
    {
        Trace.WriteLine(e.ToString());
    
        OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
        response.StatusCode = System.Net.HttpStatusCode.UnsupportedMediaType; // or anything you want
        response.StatusDescription = e.Message;
        return null; // I was returning a class
    }
    

    所以我建议您创建一个帮助代码,为您创建相关的错误代码并放入响应中。

    【讨论】:

    • 每个服务方法都应该添加这样的catch,对吧?或者有没有办法在某个地方只写一次来处理所有异常?我喜欢基于行为的方法,因为它为所有异常定义了一个通用处理程序,而且我不必担心每个方法的处理和处理异常。最好的事情是我为端点中的所有服务定义了一个处理器。用你的方法我无法做到这一点,可以吗?
    • 设置StatusDescription没有效果!响应始终具有通用状态描述。有办法解决吗?
    • 它有。您可以使用 fiddler 在来自服务器的传出消息中检查这一点,...。但您往往会发现各种浏览器或不同的实现可能会忽略描述,而只是使用代码映射到预定义的消息。我正在制作一个 Android 应用程序时遇到了这个问题,我最终设置了描述并更改了方法签名,以便我可以返回一个字符串。哎呀! 这就是我再也不会使用 WCF REST 的原因。
    • @Aliostad 您是否考虑过为 StatusMessage 返回自定义响应 HEADER 值?我不明白客户端不尊重为 StatusDescription 设置的值是 WCF 的错吗?也许我错过了什么?
    • 并非如此。这将是反 HTTP 的。状态代码是状态代码,尽管您可以有自定义代码,例如909 “我的自定义状态”。
    【解决方案2】:

    这是我过去所做的

        public class MyServerBehavior : IServiceBehavior {
    
            public void AddBindingParameters(ServiceDescription serviceDescription,
                 ServiceHostBase serviceHostBase, 
                 Collection<ServiceEndpoint> endpoints, 
                 BindingParameterCollection bindingParameters) {
    
            }
    
            public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
                                              ServiceHostBase serviceHostBase) {
    
                foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers) {
                    chDisp.IncludeExceptionDetailInFaults = true;
                    if (chDisp.ErrorHandlers.Count > 0) {
                        // Remove the System.ServiceModel.Web errorHandler
                        chDisp.ErrorHandlers.Remove(chDisp.ErrorHandlers[0]);  
                    }
                    // Add new custom error handler
                    chDisp.ErrorHandlers.Add(new MyErrorHandler());
    
                }
    
            }
    
            public void Validate(ServiceDescription serviceDescription, 
                                 ServiceHostBase serviceHostBase) {
            }
    
        }
    

    MyErrorHandler 是我实现 IErrorHandler 的类。

    【讨论】:

    • 这看起来与我所做的非常相似。它适用于 REST 服务,还是仅适用于 SOAP?如果它适用于 REST 服务,您是如何配置该服务的?如果只是为了 SOAP,那么谢谢你,但 REST 是一个完全不同的故事,就我现在所看到的而言。
    • @Michael 我是为 REST 服务做的。我是自托管的,实际上创建了自己的派生服务主机来设置行为。都是基于代码的,没有 XML。
    • 自托管,我明白了...这就是我正在考虑的,但被认为太复杂了。谢谢!
    猜你喜欢
    • 2014-11-22
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 1970-01-01
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多