2017-06-14 26 views
0

我有Asp.Net.Core應用程序,其中必須有一些日誌記錄,今天我試圖添加異常處理中間件。我已使用asp.net DiagonsticsUseExceptionHandler。問題是,當我的日誌中間件是後ExceptionHandler中間件在Asp.Net Core中記錄中間件,之後使用UseExceptionHandler

app.UseExceptionHandler("/error"); 

app.UseSerilogMiddleware(); 

這wasnot redirectig我到我的自定義錯誤頁的時候有一些例外。

public async Task Invoke(HttpContext httpContext) 
     { 
      if (httpContext == null) 
      { 
       Log.Write(LogEventLevel.Fatal, "No HTTP context found!"); 
      } 

      HttpRequest request = httpContext.Request; 
      var logger = GetExtendedLogger(request); 

      var stopwatchStart = Stopwatch.GetTimestamp(); 
      try 
      { 
       var originalResponseBody = httpContext.Response.Body; 
       using (MemoryStream stream = new MemoryStream()) 
       { 
        **httpContext.Response.Body = stream;** 

        await _next(httpContext); 

        stream.Seek(0, SeekOrigin.Begin); 
        var responseBody = new StreamReader(stream).ReadToEnd(); 

        var elapsedMs = GetElapsedMilliseconds(stopwatchStart, Stopwatch.GetTimestamp()); 
        var statusCode = httpContext.Response?.StatusCode; 

        var level = GetLogEventLevel(statusCode); 

        var log = Log 
        .ForContext("RequestHeaders", httpContext.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()), destructureObjects: true) 
        .ForContext("RequestHost", httpContext.Request.Host) 
        .ForContext("RequestProtocol", httpContext.Request.Protocol); 
        logger.Write(level, MessageTemplate, httpContext.Request.Method, httpContext.Request.Path, statusCode, elapsedMs, responseBody); 

        stream.Seek(0, SeekOrigin.Begin); 
        await stream.CopyToAsync(originalResponseBody); 
       } 

      } 
      // Never caught, because LogException() returns false. 
      catch (Exception ex) when (AddExceptionLogEntry(logger, httpContext, GetElapsedMilliseconds(stopwatchStart, Stopwatch.GetTimestamp()), ex)) 
      { 
      } 
     }' 

這是記錄中間件的一部分,但是我發現了什麼是造成問題,但我沒有解釋它。問題是在這一行httpContext.Response.Body = stream;當我刪除響應身體流到一切正常工作。

P.S.該記錄方法是將文件從here

回答

1

TL粘貼; DR:不要寫入流,UseExceptionHandler之前否則錯誤中間件不能寫入重定向頭。

stream.Seek(0, SeekOrigin.Begin); 
await stream.CopyToAsync(originalResponseBody); 

在調用異常中間件之前,您正在寫入響應流,因此重定向無法工作。 HTTP中的重定向是一個響應,它返回http代碼301或302,並帶有新的url的Location: http://example.com標題。

但是,當您寫入流中時,標頭已被刷新並且不能再被更改。

+0

我看到..但爲什麼刪除'httpContext.Response.Body =流;'身體設置到新創建的流這一行修復了這個問題? –

+1

很簡單:因爲如果你移除了'httpContext.Response.Body = stream;',底層的中間件從不向內存流中寫任何東西,所以內存流是** EMPTY **。當你返回到你的中間件時,'await stream.CopyToAsync(originalResponseBody);'也不要寫任何東西,因爲它包含0字節的數據,所以沒有東西會通過線路發送到客戶端,最終允許異常中間件寫它的標題 – Tseng

+1

結論:您將不得不將中間件分成兩部分。第一個使用帶有AddExceptionLog的「try/catch」的中間件被註冊** AFTER **異常中間件和另一個使用內存流的middlware並記錄您放置的成功調用** BEFORE **異常中間件 – Tseng

相關問題