在Asp.Net Core中记录中间件,然后使用UseExceptionHandler记录

时间:2017-06-14 14:50:08

标签: c# asp.net asp.net-core stream middleware

我有Asp.Net.Core应用程序,其中必须有一些日志记录,今天我尝试添加异常处理中间件。我使用了来自UseExceptionHandler的{​​{1}}。问题是当我的日志中间件在asp.net Diagonstics中间件

之后
ExceptionHandler

当出现异常时,我没有重定向到我的自定义错误页面。

app.UseExceptionHandler("/error");

app.UseSerilogMiddleware();

这是日志记录中间件的一部分,但是我发现了导致问题的原因,但我没有解释它。问题出在这一行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)) { } }' 当我删除将响应主体设置为流时,一切正常。

P.S。记录方法是从here

复制粘贴的

1 个答案:

答案 0 :(得分:1)

TL; DR :在UseExceptionHandler之前不要写入流,否则错误中间件无法写入重定向标头。

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

在调用异常中间件之前,您正在写入响应流,因此重定向无法正常工作。 HTTP中的重定向是一个响应,它返回带有新URL的Location: http://example.com标头的http代码301或302。

但是当您写入流时,标题已经刷新,无法再更改。