Home > Enterprise >  .NET 6 Logging middleware
.NET 6 Logging middleware

Time:05-22

We are trying to create a middleware that allows you to log in to an external service the body of an HTTP response.

We tried replacing it with a MemoryStream, but when we try to read it it turns out to be closed.

Could anyone help us?

Thanks in advance

Here is the code:

public class LogMiddleware 
{
    private readonly RequestDelegate _next;

    public LogMiddleware(RequestDelegate next) 
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context) 
    {
        var originBody = context.Response.Body;
        try 
        {
            var memStream = new MemoryStream();
            context.Response.Body = memStream;

            await _next(context).ConfigureAwait(false);

            memStream.Position = 0;
            var responseBody = new StreamReader(memStream).ReadToEnd();

            var memoryStreamModified = new MemoryStream();
            var sw = new StreamWriter(memoryStreamModified);
            sw.Write(responseBody);
            sw.Flush();
            memoryStreamModified.Position = 0;

            await memoryStreamModified.CopyToAsync(originBody).ConfigureAwait(false);
        } 
        finally 
        {
            context.Response.Body = originBody;
        }
    }
}

CodePudding user response:

There is a lot of good discussion on this in the following StackOverflow question: How to read ASP.NET Core Response.Body?

Because this current question calls out.NET 6, I'd specifically direct attention to this answer, which cuts through a lot of previous workarounds: https://stackoverflow.com/a/70477179/13374279

Summing that up, managing the request and response streams is a non-trivial challenge for a variety of reasons outlined in that question (buffers, conversions, leaks, data size). Depending on the level of control you need to exert over the logging parameters, you may find it beneficial just to use the built-in HttpLoggingMiddleware.

It can be registered with:

builder.Services.AddHttpLogging(opts => 
{
    opts .LoggingFields = HttpLoggingFields.ResponseBody;
});

and then added to the pipeline with app.UseHttpLogging(), at which point you could hook into the ASP NET Core ILogger to pick up the response body as part of your logging implementation:

https://source.dot.net/#Microsoft.AspNetCore.HttpLogging/HttpLoggingExtensions.cs,27

Thanks to open source, you can dig into how Microsoft implemented that middleware here if you need to build something more robust or with deeper hooks: https://source.dot.net/#Microsoft.AspNetCore.HttpLogging/HttpLoggingMiddleware.cs,35c5841599b94285

The key element is the use of the IHttpResponseBodyFeature implementation, which is not heavily documented but is the abstraction point for hooking into that part of the request/response pipeline since 3.x. Rick Strahl has a post on it in his blog that shows some of the depth of implementation required there:

https://weblog.west-wind.com/posts/2020/Mar/29/Content-Injection-with-Response-Rewriting-in-ASPNET-Core-3x

  • Related