2012-08-08 67 views
13

我在我的mvc具有全球ExceptionFilter返回例外\的WebAPI申请注册为:如何优雅地从的WebAPI消息处理程序

public virtual void RegisterHttpFilters(HttpConfiguration config) 
{ 
    config.Filters.Add(new MyExceptionFilter(_exceptionHandler)); 
} 

其中MyExceptionFilter是:

public class MyExceptionFilter : ExceptionFilterAttribute 
{ 
    private readonly IMyExceptionHandler m_exceptionHandler; 

    public MyExceptionFilter(IMyExceptionHandler exceptionHandler) 
    { 
     m_exceptionHandler = exceptionHandler; 
    } 

    public override void OnException(HttpActionExecutedContext context) 
    { 
     Exception ex = context.Exception; 
     if (ex != null) 
     { 
      object response = null; 
      HttpStatusCode statusCode = m_exceptionHandler != null 
       ? m_exceptionHandler.HandleException(ex, out response) 
       : HttpStatusCode.InternalServerError; 
      context.Response = context.Request.CreateResponse(statusCode, response ?? ex); 
     } 

     base.OnException(context); 
    } 
} 

该过滤器返回的所有异常作为json对象,并允许一些IMyExceptionHandler实现来定制返回的对象。

这一切都很好。直到我有我的一些消息处理程序的异常:

public class FooMessageHandler : DelegatingHandler 
{ 
    private readonly Func<IBar> _barFactory; 
    public FooMessageHandler(Func<IBar> barFactory) 
    { 
     _barFactory = varFactory; 
    } 

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     request.Properties["MY_BAR"] = _barFactory(); 
     return base.SendAsync(request, cancellationToken); 
    } 
} 

正如你可以看到这个处理程序创建的一些组件,并把它放到当前的HTTP请求消息。 当FuncOfIBar发生异常时,我会得到死亡黄色屏幕。我的ExceptionFilter没有被调用。

我想专门捕获在消息处理异常,并返回HttpResponseException,但它不会改变任何东西 - 仍然得到YSOD:

public class XApplicationInitializerMessageHandler : DelegatingHandler 
{ 
    private readonly Func<IXCoreApplication> _appFactory; 
    private readonly IXExceptionHandler m_exceptionHandler; 

    public XApplicationInitializerMessageHandler(Func<IXCoreApplication> appFactory, IXExceptionHandler exceptionHandler) 
    { 
     ArgumentValidator.EnsureArgumentNotNull(appFactory, "appFactory"); 
     _appFactory = appFactory; 
     m_exceptionHandler = exceptionHandler; 
    } 

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     try 
     { 
      request.SetApplication(_appFactory()); 
     } 
     catch (Exception ex) 
     { 
      object resultObject = null; 
      HttpStatusCode statusCode = m_exceptionHandler != null 
       ? m_exceptionHandler.HandleException(ex, out resultObject) 
       : HttpStatusCode.InternalServerError; 
      HttpResponseMessage responseMessage = request.CreateResponse(statusCode, resultObject ?? ex); 

      throw new HttpResponseException(responseMessage); 
     } 
     return base.SendAsync(request, cancellationToken); 
    } 
} 

}

我想我的应用程序的行为是无论发生什么异常:在ApiController或消息处理程序中。

如何做到这一点?

我知道Application_Error,但我想保持HttpApplication定制不可触摸。

+0

http://stackoverflow.com /问题/ 13013973/ASP网的Web-API的默认错误信息 – Timeless 2015-11-18 16:19:11

回答

8

不是引发HttpResponseException我应该只是返回的HttpResponseMessage

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
{ 
    try 
    { 
     request.SetApplication(_appFactory()); 
    } 
    catch (Exception ex) 
    { 
     object resultObject = null; 
     HttpStatusCode statusCode = m_exceptionHandler != null 
      ? m_exceptionHandler.HandleException(ex, out resultObject) 
      : HttpStatusCode.InternalServerError; 
     HttpResponseMessage responseMessage = request.CreateResponse(statusCode, resultObject ?? ex); 

     return Task<HttpResponseMessage>.Factory.StartNew(() => responseMessage); 
    } 
    return base.SendAsync(request, cancellationToken); 
} 
5

我有更迭做的是使用基于属性的方法。你把一个自定义属性上的每一个应该使用异常处理的行动:

[ExceptionHandling] 
public IEnumerable<string> Get() 

您的自定义异常处理属性来实现这样的:

public class ExceptionHandlingAttribute : ExceptionFilterAttribute 
{ 
    public override void OnException(HttpActionExecutedContext context) 
    {} 

正如你可以看到你,自定义属性从ExceptionFilterAttribute继承。然后您只需重写OnException方法。然后,您可以查看异常的类型,并根据业务规则处理它或满足您的需求。在某些情况下,您可能会吞服服务器上的异常。如果你想通知客户端,你可以抛出一个HttpResponseException,它可以容纳所有相关信息,如消息,调用堆栈,内部异常等。

欲了解更多灵感,请看这个伟大的博客文章:ASP.NET Web API Exception Handling

5

我与全局异常过滤器没有运行相同的问题。解决方案是Web API异常过滤器必须配置在与ASP.NET MVC异常过滤器不同的全局集合中。

所以要配置ASP。NET MVC的错误处理,你可以运行:

System.Web.Mvc.GlobalFilters.Filters.Add(new MyMvcExceptionFilter()); 

但对Web API的错误处理,你必须运行:

System.Web.Http.GlobalConfiguration.Configuration.Filters.Add(new MyWebApiExceptionFilter()); 

从我用的Web API经验有限这种情况是典型的:表面上使用的图案将非常类似于ASP.NET MVC,因此很快就熟悉了。这就产生了这样的错觉:编写一段代码会对两个框架产生影响,但实际上它们的实现在很大程度上或完全独立,您需要编写两个非常相似的代码版本工作。基于Web API异常处理

很好的参考:http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling

2

在startup.cs:

config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler()); 

我发现,使用GlobalExceptionHandler能赶上在委托处理异常,并返回定制JSON对象。

0

我发现这个博客有很好的例子: http://nodogmablog.bryanhogan.net/2016/07/getting-web-api-exception-details-from-a-httpresponsemessage/

我采用了一些更新的代码:使用

if ((int)response.StatusCode >= 400) 
{ 
     exceptionResponse = JsonConvert.DeserializeObject<ExceptionResponse>(LogRequisicao.CorpoResposta); 
     LogRequisicao.CorpoResposta = exceptionResponse.ToString() ; 
     if (exceptionResponse.InnerException != null) 
      LogRequisicao.CorpoResposta += "\r\n InnerException: " + exceptionResponse.ToString(); 
} 

对象:

public class ExceptionResponse 
    { 
     public string Message { get; set; } 
     public string ExceptionMessage { get; set; } 
     public string ExceptionType { get; set; } 
     public string StackTrace { get; set; } 
     public ExceptionResponse InnerException { get; set; } 

     public override String ToString() 
     { 
      return "Message: " + Message + "\r\n " 
       + "ExceptionMessage: " + ExceptionMessage + "\r\n " 
       + "ExceptionType: " + ExceptionType + " \r\n " 
       + "StackTrace: " + StackTrace + " \r\n ";   
     } 
    } 
相关问题