2011-07-18 204 views
2

我有一个定制的IErrorHandler一个REST WCF服务,使我能赶上我在服务中的所有捕获的异常,并返回一个自定义错误消息,正确的HTTP状态代码(500),并记录错误。REST WCF服务与IErrorHandler抓住SerializationExceptions

问题是,IErrorHandler将捕获不是源自我的代码的异常,所以如果我例如对具有无效JSON数据的服务进行POST,我将得到一个SerializationException。如果不是我的IErrorHandler,那么这个异常将被转换为状态码为BadRequest 400的WebFaultException,我将像处理所有其他未捕获的异常一样处理它。

有没有办法处理这些情况,或者我应该在我的IErrorHandler中捕获SerializationException并在那里设置BadRequest?如果没有来自我的代码的其他异常可能来自WCF堆栈的其他异常?

更新:新增IErrorHandler.ProvideFault

public void ProvideFault(Exception error, MessageVersion version, ref Message fault) 
    { 
     Guid loggingId = Guid.NewGuid(); 
     error.Data["ExceptionLoggingId"] = loggingId; 

     if (error is SecurityTokenException) 
     { 
      fault = Message.CreateMessage(version, string.Empty, String.Format("{0}. The error identifier is {1}", error.Message, loggingId), new DataContractJsonSerializer(typeof(string))); 
      fault.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Json)); 

      webOperationContextWrapper.SetOutgoingResponseStatusCode(HttpStatusCode.Unauthorized); 
     } 
     else 
     { 
      if (error is SerializationException) 
      { 
       // TODO: What if the SerializationException originates from within the service? 
       // SerializationException due to malformed JSON 
       return; 
      } 

      fault = Message.CreateMessage(version, string.Empty, String.Format("An unknown error has occurred. The error identifier is {0}", loggingId), new DataContractJsonSerializer(typeof(string))); 
      fault.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Json)); 

      webOperationContextWrapper.SetOutgoingResponseStatusCode(HttpStatusCode.InternalServerError); 
     } 
} 
+0

如果您在ProvideFault中未分配故障消息,会发生什么情况? –

+0

然后它按预期工作;客户端将收到http状态码400.但是,这意味着我要检查IErrorHandler中的SerializationExceptions。但是,如果SerializationException是从我的服务而不是来自WCF的堆栈,那么它是一个服务器错误(有些系列化我做了错误),我想返回状态代码500。你看这个问题? – Joel

+0

我说我的实现澄清我的意思 – Joel

回答

1

我遇到类似的问题,我的实现。

我的解决方案一直使用命名空间来确定异常的来源。

if (!error.StackTrace.TrimStart().StartsWith("at " + this.GetType().Namespace.Split('.')[0])) 
    return; 

这适用于我目前的项目。但取决于你的项目,它可能不会...

+0

感谢您的提示!但我想要更少的硬编码。截至目前,我正在捕获序列化异常并将它们转换为正确的状态码 – Joel

0

我认为@RichardBlewett它是正确的。你将要创建一个自定义异常类并抛出它,在错误处理程序中检查该类型,然后让标准序列化异常正常流动。这对我来说似乎是最好的设计模式。

然后你得到一个类型安全的,不过,如果您删除或更改,错误处理程序代码将无法编译或将与类型得到重构,如果你通过VS.做像这样测试命名空间可能不太明智(虽然非常聪明),因为它在编译时并不直接绑定到任何类型。如果你改变命名空间,你会遇到一个难以追踪的问题。