2012-08-08 57 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 ";   
     } 
    }