3

It seems .NET Core 3.1 makes it very difficult to access the raw HTTP request body following an exception

The core of the issue seems to be you can't rewind the stream to the beginning so the whole thing can be read

In the below sample the output is:

Content-Length: 19
Can't rewind body stream. Specified method is not supported.
Body:

If I remove the Seek, there's no exception, but of course the body comes back as an empty string, because it's already been processed

There is some new plumbing based around the Pipeline API involving Request.BodyReader but they suffer from the same problem.

All I need to do, following an exception, is dump the full request to a log file including the body content. Surely this should not be so difficult?

   public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {            
        app.UseExceptionHandler(errorApp =>
        {
            errorApp.Run(async context =>
            {
                Console.WriteLine("Content-Length: " + context.Request.Headers["Content-Length"]);
                string tmp;
                try
                {
                    context.Request.Body.Seek(0, SeekOrigin.Begin);
                }
                catch(Exception ex)
                {
                    Console.WriteLine("Can't rewind body stream. " + ex.Message);
                }
                using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8))
                {

                    tmp = await reader.ReadToEndAsync();
                }

                Console.WriteLine("Body: " + tmp);

            });
        });

        app.UseStaticFiles();
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
            endpoints.MapDefaultControllerRoute();
        });
    }
user69374
  • 541
  • 1
  • 5
  • 13
  • why do you need to do a repeated read of the request body on exception. – Saravanan Apr 12 '20 at 17:42
  • 2
    Lots of use cases - logging for one. You want to know what the request looked like when it failed. Security - if it's malicious there may be information in there that would be useful for tracing etc. Makes perfect sense to try to capture exception content. – Rick Strahl Apr 24 '20 at 03:16

2 Answers2

4

Please review answer by Stephen Wilkinson

Add the following to your code:

Startup.cs

app.Use((context, next) =>
{
    context.Request.EnableBuffering(); // calls EnableRewind() `https://github.com/dotnet/aspnetcore/blob/4ef204e13b88c0734e0e94a1cc4c0ef05f40849e/src/Http/Http/src/Extensions/HttpRequestRewindExtensions.cs#L23`
    return next();
});

You should then be able to rewind as per your code above:

string tmp;
try
{
    context.Request.Body.Seek(0, SeekOrigin.Begin);
}
catch(Exception ex)
{
    Console.WriteLine("Can't rewind body stream. " + ex.Message);
}
using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8))
{

    tmp = await reader.ReadToEndAsync();
}
Lance
  • 592
  • 2
  • 7
  • 13
0

It works for me.

StringBuilder body = new StringBuilder();
var req = context.Request;

// Allows using several time the stream in ASP.Net Core
req.EnableBuffering();

using (StreamReader reader = new StreamReader(req.Body, Encoding.UTF8, true, 1024, true))
{
    string line;
    while ((line = reader.ReadLineAsync().Result) != null)
    {
        body.Append(line);
    }
}
req.Body.Position = 0;
_logger.LogInformation($"Body: {body.ToString()}");

From link How to read request body in an asp.net core webapi controller?

Kha Bui
  • 1
  • 2