8

I'm developing asp .net core 2.1 WEB-API application.

I use ILogger with configuration:

"Logging": {
"LogLevel": {
  "Default": "Debug",
  "System": "Information",
  "Microsoft": "Information"
}

And on request i see log:

info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] Executing action method ActivationService.Controllers.ActivationController.Post (ActivationService) with arguments (ActivationService.Contracts.ActivationRequest) - Validation state: Valid

and

Executed action method ActivationService.Controllers.ActivationController.Post (ActivationService), returned result Microsoft.AspNetCore.Mvc.ObjectResult in 174605.9201ms.

Is there way to confugure asp.net to log with trace body of response and request?

1 Answer 1

6

Yes, you can implement logging middleware:

public class RequestResponseLoggingMiddleware
    {
        private readonly RequestDelegate next;
        private readonly ILogger logger;

        public RequestResponseLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
        {
            this.next = next;
            logger = loggerFactory.CreateLogger<RequestResponseLoggingMiddleware>();
        }

        public async Task Invoke(HttpContext context)
        {
            context.Request.EnableRewind();

            var buffer = new byte[Convert.ToInt32(context.Request.ContentLength)];
            await context.Request.Body.ReadAsync(buffer, 0, buffer.Length);
            var requestBody = Encoding.UTF8.GetString(buffer);
            context.Request.Body.Seek(0, SeekOrigin.Begin);

            logger.LogInformation(requestBody);

            var originalBodyStream = context.Response.Body;

            using (var responseBody = new MemoryStream())
            {
                context.Response.Body = responseBody;

                await next(context);

                context.Response.Body.Seek(0, SeekOrigin.Begin);
                var response = await new StreamReader(context.Response.Body).ReadToEndAsync();
                context.Response.Body.Seek(0, SeekOrigin.Begin);

                logger.LogInformation(response);
                await responseBody.CopyToAsync(originalBodyStream);
            }
        }
    }

And then add it to application Builder in Configure method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ....
    app.UseMiddleware<RequestResponseLoggingMiddleware>();
}
Sign up to request clarification or add additional context in comments.

5 Comments

1) in your example i have to change from "context.Request.Body = body;" to "context.Request.Body.Position = 0;", otherwise request came null in controller 2) it's ok, and may be i'll use it. But may be there is a way to configure standard asp logger to do it?
@TimurLemeshko, unfortunately, there is no way to configure logger to do that.
This won't log outgoing calls
Will not work with Transfer-Encoding: chunked as Content-Length header is omitted, so context.Request.ContentLength is unavailable. EnableBuffering extension is possible workaround. learn.microsoft.com/en-us/dotnet/api/…
EnableRewind is the method from Internal Asp net namespace and AFAIU it isn't guaranteed that it will work publicly. For instance, I get an error System.TypeLoadException: Could not load type 'Microsoft.AspNetCore.Http.Internal.BufferingHelper' from assembly 'Microsoft.AspNetCore.Http...' I would suggest to use "EnableBuffering()" which has the same meaning: "Ensure the request Body can be read multiple times."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.