【问题标题】:Returning Meaningful Exceptions from a WCF Project从 WCF 项目返回有意义的异常
【发布时间】:2011-02-02 12:58:37
【问题描述】:

总的来说,我对 WCF 还是很陌生。我在 ASP.NET Web 应用程序中使用相当简单的 .SVC 服务所获得的一点经验。

我第一次尝试使用 WCF 项目,结果遇到了一个大问题。

我相信大多数人都知道,出于某种奇怪的原因,在一个 web 应用程序中 customErrors 模式设置为 On

<customErrors mode = “On” />

服务(.ASMX 和 .SVC)不会向客户端返回异常详细信息。相反,异常和堆栈跟踪被清空,消息总是显示“处理请求时出错”,这根本没有帮助。

当服务直接托管在 Web 应用程序本身中时,可以通过将服务放置在专用文件夹中并将该文件夹的 customErrors 设置为“关闭”来轻松解决此限制。

但是,我遇到了同样的问题,但没有从位于单独 WCF 项目中的服务返回异常。问题是,我不知道如何解决这个问题。

简而言之:我需要让我的 WCF 项目服务向客户端发送真正的异常——或者至少是原始异常消息,而不是“处理请求时出错”。

编辑:我可能应该在这里指出,我想返回异常的原因是我经常通过 Ajax (jQuery) 从客户端调用这些服务,并且想如果它是“正常”返回(例如,使用绿色文本),则以不同的方式格式化返回消息,如果是错误则使用红色文本。我在 $.ajax 对象的错误处理程序中处理消息格式,这显然只会在服务失败时运行。

我还应该指出,关闭 customErrors 一切正常:

<customErrors mode = “Off” />

所以,我想也许可以设置一些配置属性来阻止 ASP.NET 运行时在使用 customErrors 时终止我的异常。

Here 是我在此找到的一些相关信息。

【问题讨论】:

    标签: web-services exception-handling wcf


    【解决方案1】:

    您还有另一种选择,可以捕获您想向客户端冒泡的异常,并返回服务故障。

    还有更多的设计工作需要进行,因为您必须自己设计故障合同,但它让您可以灵活地将您想要的任何东西返回给客户。因此,您可以设计一个详细说明错误的合约,并在您认为必要时进行堆栈跟踪。

    例子:

    [DataContract(Namespace = "urn:// or http://....")]
    public class ClientNeedsToKnowFault
    {
        [DataMember]
        public List<Error> Errors
        {
            get { return _errors; }
            set { _errors = value; }
        }
    
         ....
        public ClientNeedsToKnowFault() { }
    
        public ClientNeedsToKnowFault(string message)
        {
            Message = message;
            Errors = new List<Error>() { new Error(message) };
        }
    
    
    
        ...
        //Helper method to throw
         public static void ThrowFault(string message, List<Error> errorList)
        {
            throw new FaultException<ClientNeedsToKnowFault>(new ClientNeedsToKnowFault(message, errorList));
        }
    

    一旦你设计了你的错误,你就可以为服务方法添加一个额外的属性。

    [FaultContract(typeof(ClientNeedsToKnowFault))]
     void MyServiceMethod();
    

    最后一步就是扔掉它。正如你在上面看到的,我只是放了一个辅助方法来抛出它,因为我认为 FaultException 过程有点混乱。

    我会说这种方法的主要缺点是必须在客户端捕获故障。但如果信息重要到足以返回故障,您可能需要这种复杂性。

    【讨论】:

    • 我实际上尝试过这个,但是,当 时,异常消息(实际上是整个异常对象和堆栈跟踪)被抑制了。使用 ,一切正常。这让我相信,不知何故,我必须以某种方式将异常偷偷溜过 ASP.NET 运行时。 ;)
    • 您需要在服务器端捕获异常,并重新生成您的代理。如果您需要我将其添加到帖子中,我可以。
    • 我发现了异常。但正如我所说,我得到的只是消息““处理请求时出错”。不确定你所说的“重新生成代理”是什么意思——也许这就是我所缺少的......
    • 顺便问一下,在这个例子中,“Error”也是一个自定义类吗?
    • 是的,对不起,我应该这么说。我的错误类是 3 个属性消息、类别、优先级。
    【解决方案2】:

    这里真正的答案是,您可能应该始终避免将真正的异常冒泡给调用者。 “ServiceResponse”模式在这里很有用。这个想法是,您将返回一个“ServiceResponse”类,其中包含您的服务所需的任何响应值,但除了允许您返回 Exception 对象的属性之外,还具有某种“IsError”标志。

    然后,服务可以简单地处理所有错误并返回该信息:

    public ServiceResponse MyService()
    {
      try { 
        // ... do work here
        return new ServiceResponse { WhateverReturnValue = true };
      } catch(Exception e) {
        return new ServiceResponse { IsError = true, Error = e };
      }
    }
    

    【讨论】:

    • 我已经看到这种模式被大量使用了,我们对其进行了更多的概括,并有一个值对象和错误列表,然后根据列表不为空并且其中包含某些内容来派生 HasError。跨度>
    • 是的,它有很多变体,但根本概念是无论是否存在内部故障,您都应该返回一致的值。客户端应该只需要处理未找到端点之类的事情(即他们的配置问题)
    • 这似乎是一种有效的方法。这里唯一的问题是,就客户端而言,服务将始终返回“良好”响应,这使得很难针对错误条件对返回的消息进行不同的格式设置。 (请参阅我在原帖中的编辑)
    • 哦,不,这不是一个好方法。接下来,您将返回错误编号。
    • 糟糕的建议恕我直言。作为一等公民,SOAP 中存在错误是有原因的。您不应该将所有异常都作为故障泄漏出来,但您应该使用故障来报告逻辑异常。
    【解决方案3】:

    您可以查看实现IErrorHandler 接口以捕获任何异常并返回您的合同指定的FaultException

    【讨论】:

    • 这是一个非常糟糕的主意,您不想从服务中抛出异常(使用错误),并且通常您不想将异常的堆栈跟踪暴露给最终用户(安全)。
    • 好点...开始编辑以删除对 IncludeExceptionDetailInFaults 属性的引用;)
    • 这是一个比你的第一个更好的建议!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 2020-09-27
    • 1970-01-01
    • 2011-08-13
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多