我有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