2014-03-04 58 views
19

爲什麼自定義的ExceptionHandler永遠不會被調用,而是返回一個標準響應(不是我想要的)?WebApi v2 ExceptionHandler not called

在控制器或在儲存庫中註冊這樣

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

和這樣

public class GlobalExceptionHandler : ExceptionHandler 
{ 
    public override void Handle(ExceptionHandlerContext context) 
    { 
     context.Result = new ExceptionResponse 
     { 
      statusCode = context.Exception is SecurityException ? HttpStatusCode.Unauthorized : HttpStatusCode.InternalServerError, 
      message = "An internal exception occurred. We'll take care of it.", 
      request = context.Request 
     }; 
    } 
} 

public class ExceptionResponse : IHttpActionResult 
{ 
    public HttpStatusCode statusCode { get; set; } 
    public string message { get; set; } 
    public HttpRequestMessage request { get; set; } 

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) 
    { 
     var response = new HttpResponseMessage(statusCode); 
     response.RequestMessage = request; 
     response.Content = new StringContent(message); 
     return Task.FromResult(response); 
    } 
} 

實現,並且拋出這樣的(試驗)

throw new NullReferenceException("testerror"); 

UPDATE

我沒有其他ExceptionFilter

我發現這種行爲觸發:

給定的URL

GET http://localhost:XXXXX/template/lock/someId 

發送這個頭,我ExceptionHandler作品

Host: localhost:XXXXX 

發送這個頭,它不工作和內置處理程序返回錯誤代替

Host: localhost:XXXXX 
Origin: http://localhost:YYYY 

這可能是CORS請求(我使用帶有通配符的全局WebAPI CORS包)或最終是我的ELMAH記錄器的問題。它也在Azure(網站)上託管時發生,但內置錯誤處理程序不同。

任何想法如何解決這個問題?

+0

你碰巧有一個異常過濾器呢?也可以大家分享您的控制器或庫代碼的樣子......我們想確保你沒有地方捕獲它並將其轉換爲HttpResponseException什麼在這種情況下,異常處理程序不會被調用。 –

+0

@KiranChalla:上面有趣的更新,謝謝! –

回答

24

原來,默認值只處理最外層的異常,而不是存儲庫類中的異常。所以,下面已經被覆蓋,以及:

public virtual bool ShouldHandle(ExceptionHandlerContext context) 
{ 
    return context.ExceptionContext.IsOutermostCatchBlock; 
} 

更新1

的WebAPI V2不使用IsOutermostCatchBlock了。無論如何,我的實現沒有任何變化,因爲ShouldHandle中的新代碼仍然會阻止我的錯誤處理程序。所以我使用這個和我的錯誤處理程序被調用一次。我以這種方式捕獲控制器和存儲庫中的錯誤。

public virtual bool ShouldHandle(ExceptionHandlerContext context) 
{ 
    return true; 
} 

更新2

由於這個問題得到了這麼多的關注,請注意,目前的解決方案是在下面的意見之一linked通過@JustAMartin。

+3

還要注意這樣一條:http://stackoverflow.com/questions/22038800/can-anyone-explain-the-work-flow-of-iexceptionhandler-with-sample-client-applica他們似乎已經取代IsOutermostCatchBlock與IsTopLevel – JustAMartin

+0

感謝@Martin的更新。仍然是一樣的,不知道爲什麼控制器錯誤不能用標準實現來處理。 –

+6

我剛剛發現異常處理與CORS的解決方案,看看這可能是對你有幫助:http://stackoverflow.com/questions/24189315/exceptions-in-asp-net-web-api-custom-exception-handler -never觸及-頂級-磨片/ 24634485#24634485看來甚至ASP.NET團隊沒有使用ShouldHandle了,但他們沒有在任何地方提到它,從而導致混亂。我建議你忘記的ExceptionHandler基類和實現解決方案ASP.NET團隊的作用:https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/ExceptionHandling/DefaultExceptionHandler.cs – JustAMartin

7

這裏真正的罪魁禍首是CorsMessageHandler由消息處理管道中的EnableCors方法插入。catch塊攔截任何異常,並轉換成一個響應,纔可以達到的httpserver try-catch塊和邏輯的ExceptionHandler可以調用

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
{ 
    CorsRequestContext corsRequestContext = request.GetCorsRequestContext(); 
    HttpResponseMessage result; 
    if (corsRequestContext != null) 
    { 
    try 
    { 
     if (corsRequestContext.IsPreflight) 
     { 
     result = await this.HandleCorsPreflightRequestAsync(request, corsRequestContext, cancellationToken); 
     return result; 
     } 
     result = await this.HandleCorsRequestAsync(request, corsRequestContext, cancellationToken); 
     return result; 
    } 
    catch (Exception exception) 
    { 
     result = CorsMessageHandler.HandleException(request, exception); 
     return result; 
    } 
    } 
    result = await this.<>n__FabricatedMethod3(request, cancellationToken); 
    return result; 
} 
+1

你知道任何解決方法嗎? – Zero3

+1

解決方法可以在http://stackoverflow.com/questions/24189315/exceptions-in-asp-net-web-api-custom-exception-handler-never-reach-top-level-whe/24634485#24634485找到 – 0xced