2010-12-16 174 views
8

我有很多遗留代码,现在是WCF REST服务的后端 - 它以前是通常的WCF服务后端,如果这很重要的话。我想实现一种机制,可以捕捉任何方法中的任何异常并分析它。如果它是一个已知的错误,它将被处理并变成一个友善的外观错误。WCF REST服务 - 通用异常处理

我知道我可以抛出FaultExceptionWebProtocolException而不是'平常'异常,但是有很多地方在代码中抛出异常,并且寻找所有这些异常是一个非常痛苦的选择。

我想补充一点,创建一个新的行为凌驾于标准WebHttpBehavior.AddServerErrorHandlers方法,并增加了我的错误处理程序(IErrorHandler实现)到终点调度错误处理程序集合中的端点行为扩展。在错误处理程序内部,我分析异常并基于此异常创建(或不创建)期望的故障。

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

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

非常感谢!

回答

7

当您将WCF SOAP服务更改为REST时,错误报告和处理更改的整个思路。

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

这里是一个catch片段:

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 
} 

所以我建议您创建为您创建相应的错误代码,放在了响应的辅助代码。

+0

这种捕获应该被添加到每种服务方法,对吧?或者有没有办法将它写在某个地方只处理一次以处理所有异常?我喜欢基于行为的方法,因为它为所有异常定义了一个通用处理程序,并且我不必担心为每个单一方法处理和处理异常。最好的情况是我为端点中的所有服务定义了一个处理器。我无法用你的方法达到这个目标,我可以吗? – 2010-12-17 08:30:07

+0

设置'StatusDescription'不起作用!响应始终具有通用状态描述。无论如何解决它? – Hemant 2011-01-13 07:19:30

+0

它有。您可以使用fiddler检查服务器发出的消息中的....,但是您可能会发现,各种浏览器或不同的实现可能会忽略该描述,只是使用代码映射到预定义的消息。我遇到了一个我正在编写的Android应用程序的问题,并最终设置了描述以及更改方法签名,以便我可以返回一个字符串。哎呀! **这就是为什么我永远不会使用WCF REST了。** – Aliostad 2011-01-13 09:19:02

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。

+0

这看起来与我所做的非常相似。它是否适用于REST服务,还是仅适用于SOAP?如果它适用于REST服务,那么您是如何配置服务的?如果仅仅用于SOAP,那么谢谢,但就我现在看到的而言,REST是完全不同的故事。 – 2010-12-17 08:32:54

+1

@Michael我为它做了REST服务。我是自我托管的,实际上创建了我自己的派生服务主机来设置行为。它都是基于代码的,没有XML。 – 2010-12-17 12:10:41

+0

自我托管,我明白了...这就是我想的但被认为太复杂。谢谢! – 2010-12-17 15:28:29