2017-04-26 45 views
2

注意:這個問題是關於elmah.io(https://elmah.io/),基於雲的異常記錄服務,而不是傳統的Elmah .Net庫。如何使elmah.io在ASP.NET Core和錯誤處理中間件上運行良好?

我正在使用ASP.NET Core並有一個簡單的異常處理中間件。

public class HandleExceptionMiddleware 
{ 
    public HandleExceptionMiddleware(RequestDelegate next) 
    { 
     Next = next; 
    } 

    RequestDelegate Next { get; } 

    public async Task Invoke(HttpContext httpContext) 
    { 
     try 
     { 
      await Next(httpContext); 
     } 
     catch (Exception ex) 
     { 
      await HandleExceptionAsync(httpContext, ex); 
     } 
    } 

    Task HandleExceptionAsync(HttpContext context, Exception ex) 
    { 
     var code = HttpStatusCode.InternalServerError; 

     if (ex is ArgumentException) 
      code = HttpStatusCode.BadRequest; 

     var result = JsonConvert.SerializeObject(new { message = ex.Message }); 
     context.Response.ContentType = "application/json"; 
     context.Response.StatusCode = (int)code; 
     return context.Response.WriteAsync(result); 
    } 
} 

這個中間件將返回取決於例外以下JSON響應,它認爲:

對於ArgumentException的:

HTTP/1.1 400 Bad Request 

{"message":""} 

對於所有其它異常:

HTTP/1.1 500 Internal Server Error 

{"message":""} 

我'd像elmah.io登錄500迴應並忽略400響應(這是默認的elmah.io配置)。然而,當異常處理程序和elmah.io在啓動時的配置掛鉤這個命令被註冊,沒有東西在elmah.io登錄:

app.UseElmahIo("API_KEY", new Guid("LOG_ID")); 
    app.UseMiddleware<HandleExceptionMiddleware>() 

但是,如果我變更登記爲以下,一切變得記錄(包括400個回覆)。這使得作爲elmah.io處理HandleExceptionMiddleware前的異常都有機會改變響應的感覺:

app.UseMiddleware<HandleExceptionMiddleware>() 
    app.UseElmahIo("API_KEY", new Guid("LOG_ID")); 

什麼是配置這些服務,使elmah.io日誌500個迴應並忽略400個反應的最好方法?

我想出的唯一解決方法是創建並註冊2個異常處理中間件而不是1個。一個之前註冊,另一個註冊在elmah.io之後。它的工作原理,但似乎有點難看:

app.UseMiddleware<HandleInternalExceptionMiddleware>() // set 500 responses (these will have already been logged in elmah.io) 
    app.UseElmahIo("API_KEY", new Guid("LOG_ID")); 
    app.UseMiddleware<HandleExternalExceptionMiddleware>() // set 400 responses but ignore exceptions that should return 500 (these won't be logged in elmah.io) 

我創建了一個示例項目在這裏演示此行爲: https://github.com/johnnyoshika/elmah-io-experiment

回答

2

配置elmah.io正確的方法,是使用行爲2.您希望調用處理異常的其他方法後調用UseElmahIo方法。這是因爲很多錯誤處理中間件(包括您的HandleExceptionMiddleware)吞下所有異常並將結果轉換爲其他內容。在你的情況下,HandleExceptionMiddleware捕獲所有異常並設置新的響應。在這種情況下,我們的中間件從未被通知過異常(正如你所提到的那樣)。

我們有幾個不同的方法來解決這個問題:調用UseMiddleware

解決方案1個

呼叫UseElmahIo並添加自定義忽略過濾器來忽略錯誤最終becomming壞請求:

app.UseMiddleware<HandleExceptionMiddleware>(); 
app.UseElmahIo("API_KEY", new Guid("LOG_ID"), new ElmahIoSettings 
{ 
    OnFilter = msg => msg.Type == typeof(ArgumentException).Name 
}); 

這種方法的不足之處在於,您需要在HandleExceptionMiddleware和yo兩者中維護一組類似的規則你的elmah.io配置。

解決方案2

呼叫UseElmahIo之前調用UseMiddleware,並指定要記錄的狀態代碼,即使(在這種情況下,通過HandleExceptionMiddleware吞噬)的異常沒有拋出:

app.UseElmahIo("API_KEY", new Guid("LOG_ID"), new ElmahIoSettings 
{ 
    HandledStatusCodesToLog = new List<int> { 404, 500, ... } 
}); 
app.UseMiddleware<HandleExceptionMiddleware>(); 

的如果採用這種方法,那麼您將需要手動指定所有狀態碼,並且拋出實際異常的信息在elmah.io上不可用。造成這種情況的原因是,HandleExceptionMiddleware使elmah.io無法查看拋出異常。

我個人比較喜歡解決方案1,因爲它確保捕獲所有異常,包括堆棧跟蹤和異常類型等信息。

+0

很好的回答!我學到了很多東西。我曾經想過,因爲默認情況下,elmah.io會記錄500個響應,所以我不必將500添加到HandledStatusCodesToLog列表中。我現在已經瞭解到,當列表中有500個時,行爲是不同的。就像你說的,解決方案2絕對不是很好的B/C堆棧跟蹤將不會被記錄。解決方案1更好,它會解決我的問題,但我認爲我會堅持使用2中間件方法,因爲這樣,我不需要在2個地方維護相同的規則。 –

相關問題