我有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
复制粘贴的答案 0 :(得分:1)
TL; DR :在UseExceptionHandler
之前不要写入流,否则错误中间件无法写入重定向标头。
stream.Seek(0, SeekOrigin.Begin);
await stream.CopyToAsync(originalResponseBody);
在调用异常中间件之前,您正在写入响应流,因此重定向无法正常工作。 HTTP中的重定向是一个响应,它返回带有新URL的Location: http://example.com
标头的http代码301或302。
但是当您写入流时,标题已经刷新,无法再更改。