Skip to content

HttpLoggingMiddleware does not log RequestBody when body is consumed by copying to another stream #49989

@olegbaslak

Description

@olegbaslak

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When HttpLoggingMiddleware is enabled and HttpContext.Request.Body is consumed by copying to another stream (calling CopyToAsync) instead of reading, an empty RequestBody is logged after an endpoint is executed.

Expected Behavior

Not empty request body is logged when calling CopyToAsync, e.g. when sending json body

{
    "Response": "Test Response"
}

it should be logged as is.

Steps To Reproduce

  1. Simple Program.cs of ASP.NET Core project that copies request into memory stream and writes it back to response:
using System.Text;
using Microsoft.AspNetCore.HttpLogging;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(options => { options.LoggingFields = HttpLoggingFields.RequestBody; });

var app = builder.Build();

app.MapGet("/", async context =>
{
    // context.Request.EnableBuffering(); // Enabling buffering "fixes" the issue

    using var tempStream = new MemoryStream();
    await context.Request.Body.CopyToAsync(tempStream);

    var responseContent = Encoding.Default.GetString(tempStream.ToArray());
    await context.Response.WriteAsync(responseContent);
});

app.UseHttpLogging();
await app.RunAsync();
  1. Send a request to / endpoint with some json body, e.g. { "Response": "Test Response" }
  2. Observe logs.

Logs:

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET https://localhost:7255/ application/json 37
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
      Request:

info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'HTTP: GET /'
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'HTTP: GET /'
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[3]
      RequestBody:
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET https://localhost:7255/ application/json 37 - 200 - - 38.6330ms

Exceptions (if any)

Enabling buffering by uncommenting context.Request.EnableBuffering(); line.

Logs in this case:

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET https://localhost:7255/ application/json 37
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
      Request:

info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'HTTP: GET /'
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[3]
      RequestBody: {
          "Response": "Test Response"
      }
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'HTTP: GET /'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET https://localhost:7255/ application/json 37 - 200 - - 25.6788ms

Probably it happens because FileBufferingReadStream calls ReadAsync methods on the inner stream (in this case inner is RequestBufferingStream) in its CopyToAsync implementation. And RequestBufferingStream, when not wrapped, does not write anything in its buffer when CopyToAsync is called.

.NET Version

7.0.203

Anything else?

ASP.NET Core: 7.0.5
IDE: Visual Studio 2022, Rider

Also reproducible for .NET 6

Metadata

Metadata

Assignees

Labels

area-middlewareIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewaresbugThis issue describes a behavior which is not expected - a bug.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions