0

In my .NET Core 3.1 app I need to log out any requests with a status code greater than 400 on my controller POST action.

To do this I have created the following ResultFilterAttribute

   public class LogFailureResponseFilter : ResultFilterAttribute
   {
        private readonly ILogger _logger;

        public LogFailureResponseFilter(ILogger<LogFailureResponseFilter> logger)
        {
            _logger = logger;
        }

        public override void OnResultExecuted(ResultExecutedContext context)
        {
            var statusCode = context.HttpContext.Response.StatusCode;
            if (statusCode >= 400)
            {
                using var reader = new StreamReader(context.HttpContext.Request.Body);
                var body = reader.ReadToEndAsync().Result; // <--- this is always null

                _logger.LogWarning($"Request failed for route path {context.HttpContext.Request.Path} with status code {statusCode}. The payload was {body}");
            }

            base.OnResultExecuted(context);
        }
   }

I have enabled buffering as per this Stack Overflow post that describes how to re-read a request body in Startup.cs as follows:

app.Use(async (context, next) => {
                context.Request.EnableBuffering();
                await next();
            });

Whenever I try to read the body it is always null - can anyone help please?

Edit: I've attempted to seek to the beginning of the stream with the following code but it results in System.NotSupportedException

var bodyStream = context.HttpContext.Request.Body;
bodyStream.Seek(0, SeekOrigin.Begin);
using var reader = new StreamReader(bodyStream);
var body = reader.ReadToEndAsync().Result;
Vinyl Warmth
  • 2,226
  • 3
  • 25
  • 50

1 Answers1

0

I tried your bodystream code under

services.Configure<ApiBehaviorOptions>(options =>
        {
            options.InvalidModelStateResponseFactory = context =>
            {

and it worked fine! Try to register it in startup.

metz
  • 11
  • 2