-
-
Save elanderson/c50b2107de8ee2ed856353dfed9168a2 to your computer and use it in GitHub Desktop.
public class RequestResponseLoggingMiddleware | |
{ | |
private readonly RequestDelegate _next; | |
private readonly ILogger _logger; | |
public RequestResponseLoggingMiddleware(RequestDelegate next, | |
ILoggerFactory loggerFactory) | |
{ | |
_next = next; | |
_logger = loggerFactory | |
.CreateLogger<RequestResponseLoggingMiddleware>(); | |
} | |
public async Task Invoke(HttpContext context) | |
{ | |
_logger.LogInformation(await FormatRequest(context.Request)); | |
var originalBodyStream = context.Response.Body; | |
using (var responseBody = new MemoryStream()) | |
{ | |
context.Response.Body = responseBody; | |
await _next(context); | |
_logger.LogInformation(await FormatResponse(context.Response)); | |
await responseBody.CopyToAsync(originalBodyStream); | |
} | |
} | |
private async Task<string> FormatRequest(HttpRequest request) | |
{ | |
var body = request.Body; | |
request.EnableRewind(); | |
var buffer = new byte[Convert.ToInt32(request.ContentLength)]; | |
await request.Body.ReadAsync(buffer, 0, buffer.Length); | |
var bodyAsText = Encoding.UTF8.GetString(buffer); | |
request.Body = body; | |
return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}"; | |
} | |
private async Task<string> FormatResponse(HttpResponse response) | |
{ | |
response.Body.Seek(0, SeekOrigin.Begin); | |
var text = await new StreamReader(response.Body).ReadToEndAsync(); | |
response.Body.Seek(0, SeekOrigin.Begin); | |
return $"Response {text}"; | |
} | |
} |
public static class RequestResponseLoggingMiddlewareExtensions | |
{ | |
public static IApplicationBuilder UseRequestResponseLogging(this IApplicationBuilder builder) | |
{ | |
return builder.UseMiddleware<RequestResponseLoggingMiddleware>(); | |
} | |
} |
Added a functioning example of what i'm seeing here: https://github.com/JustinJohnWilliams/RequestLogging
Also I notice when launching with the debugger the initial request for GET /values comes in twice. The second time around the response isn't logged.
Getting the same problem as JustinJohnWilliams. Doing a post seems to be corrupting te request body stream and results in a null object in the Controller Action.
i Tried setting the stream position back to 0, but no success.
Any one?
Try this: http://www.sulhome.com/blog/10/log-asp-net-core-request-and-response-using-middleware
it is working for me w/ Post
I am able to get the response when i do a GET. But when i do a POST, i expect my data to come to Request object. But that is missing. Can someone put your solutions?
@ajithesh try the following:
- Swap lines 33 and 34 - so the
.EnableRewind()
is before the assignment; - Between line 38 and 39 insert
body.Seek(0, SeekOrigin.Begin)
.
@petret worked like a charm
Great solution! But the statuscode 204 it's very danger for VS2017!!!
I add the following "if" before 27
//Because you change the response body which is not allowed on a 204.
if (context.Response.StatusCode!=204)
await responseBody.CopyToAsync(originalBodyStream);
Thanks @petret, the same behaviour (request body null on POSTs) on my side, and thid change solved it.
@elanderson it would be nice if you update the code with the fix.
Many thanks.
@elanderson thank you for sharing the approach of using a middleware in order to log request/responses in an asp.netcore application. However the specific solution might cause memory leak
in case of large body in request and response. Please check an alternative approach that might eradicate the risk of memory leak. Feel free to send your feedback so we can end up in a more elegant solution.
Hello all.
With every solutions posted here, I my Webapi core 2.1 still not working with POSTS requests, send for example by PostMan.
The POST requests simple does not trigger Invoke method. The GET request works like a charm.
Even doing mr. @petret alterations.
Any option?
Thanks.
Remove this part from code and it will forward body of post.
var body = request.Body;
request.EnableRewind();
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
await request.Body.ReadAsync(buffer, 0, buffer.Length);
var bodyAsText = Encoding.UTF8.GetString(buffer);
request.Body = body;
@petret It worked for me too, Thanks.
I had issue in POST
requests which request was sending null.
@shojajou check this link, you have to reset the position of the stream
I'm crying! Thank you all !!!
@ajithesh try the following:
- Swap lines 33 and 34 - so the
.EnableRewind()
is before the assignment;- Between line 38 and 39 insert
body.Seek(0, SeekOrigin.Begin)
.
Thanks!
@petret
thank uuuuuuuuuuuuu woooooooooooow!!!!!!!!
I struggelered a lot with body request null.
Tried on .NET 8 and working fine. Added some cool details and json limit (100 char) for log file size.
Request Response Logging in .Net 8
You can find all files here for implementation
This seems to be working for all of my GETs, however, my POSTs do not seem to send the body to the action method (it always shows up null). It logs correctly with the body, so I know I sent it with the request, the controller action seems to just get passed null.
[HttpPost("some_route")] public IActionResult SomeRoute(Guid id, [FromBody, Required] SomeRequest request) { //id is populated // request is null
removing the middleware, the request comes through just fine. any ideas?