I have a web API based on .net core 3.1.
I'm using the SeriLog library as a logger.
Here is my SeriLog Configuration. Serilog has been configured from 'appsettings.json'.
I need to add 'request body' parameters to log's output if it exists. Is there any way to configure this. Also, I share my log output.
I wrote a custom middleware to capture both HTTP requests and responses. It is compatible with ASP.NET Core 3.X and should also work with 2.X and .NET 5.0, although I haven't tested it with those framework versions.
Here's the link to my git repo: https://github.com/matthew-daddario/AspNetCoreRequestResponseLogger
The relevant code is this:
public class RequestResponseLoggerMiddleware
{
private readonly RequestDelegate _next;
private readonly bool _isRequestResponseLoggingEnabled;
public RequestResponseLoggerMiddleware(RequestDelegate next, IConfiguration config)
{
_next = next;
_isRequestResponseLoggingEnabled = config.GetValue<bool>("EnableRequestResponseLogging", false);
}
public async Task InvokeAsync(HttpContext httpContext)
{
// Middleware is enabled only when the EnableRequestResponseLogging config value is set.
if (_isRequestResponseLoggingEnabled)
{
Console.WriteLine($"HTTP request information:\n" +
$"\tMethod: {httpContext.Request.Method}\n" +
$"\tPath: {httpContext.Request.Path}\n" +
$"\tQueryString: {httpContext.Request.QueryString}\n" +
$"\tHeaders: {FormatHeaders(httpContext.Request.Headers)}\n" +
$"\tSchema: {httpContext.Request.Scheme}\n" +
$"\tHost: {httpContext.Request.Host}\n" +
$"\tBody: {await ReadBodyFromRequest(httpContext.Request)}");
// Temporarily replace the HttpResponseStream, which is a write-only stream, with a MemoryStream to capture it's value in-flight.
var originalResponseBody = httpContext.Response.Body;
using var newResponseBody = new MemoryStream();
httpContext.Response.Body = newResponseBody;
// Call the next middleware in the pipeline
await _next(httpContext);
newResponseBody.Seek(0, SeekOrigin.Begin);
var responseBodyText = await new StreamReader(httpContext.Response.Body).ReadToEndAsync();
Console.WriteLine($"HTTP request information:\n" +
$"\tStatusCode: {httpContext.Response.StatusCode}\n" +
$"\tContentType: {httpContext.Response.ContentType}\n" +
$"\tHeaders: {FormatHeaders(httpContext.Response.Headers)}\n" +
$"\tBody: {responseBodyText}");
newResponseBody.Seek(0, SeekOrigin.Begin);
await newResponseBody.CopyToAsync(originalResponseBody);
}
else
{
await _next(httpContext);
}
}
private static string FormatHeaders(IHeaderDictionary headers) => string.Join(", ", headers.Select(kvp => $"{{{kvp.Key}: {string.Join(", ", kvp.Value)}}}"));
private static async Task<string> ReadBodyFromRequest(HttpRequest request)
{
// Ensure the request's body can be read multiple times (for the next middlewares in the pipeline).
request.EnableBuffering();
using var streamReader = new StreamReader(request.Body, leaveOpen: true);
var requestBody = await streamReader.ReadToEndAsync();
// Reset the request's body stream position for next middleware in the pipeline.
request.Body.Position = 0;
return requestBody;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With