我有Asp.Net.Core應用程序,其中必須有一些日誌記錄,今天我試圖添加異常處理中間件。我已使用asp.net Diagonstics
的UseExceptionHandler
。問題是,當我的日誌中間件是後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
我看到..但爲什麼刪除'httpContext.Response.Body =流;'身體設置到新創建的流這一行修復了這個問題? –
很簡單:因爲如果你移除了'httpContext.Response.Body = stream;',底層的中間件從不向內存流中寫任何東西,所以內存流是** EMPTY **。當你返回到你的中間件時,'await stream.CopyToAsync(originalResponseBody);'也不要寫任何東西,因爲它包含0字節的數據,所以沒有東西會通過線路發送到客戶端,最終允許異常中間件寫它的標題 – Tseng
結論:您將不得不將中間件分成兩部分。第一個使用帶有AddExceptionLog的「try/catch」的中間件被註冊** AFTER **異常中間件和另一個使用內存流的middlware並記錄您放置的成功調用** BEFORE **異常中間件 – Tseng