Created
January 28, 2021 12:42
-
-
Save afruzan/fb380ba6235b38682bf4bbfe63018810 to your computer and use it in GitHub Desktop.
logging full request and responce (including body) in asp.net core (tested on 5 but should supports 3.1).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Http; | |
using Microsoft.Extensions.Configuration; | |
using Microsoft.Extensions.Logging; | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Threading.Tasks; | |
namespace TVS.Web.DataReceiverService.Middlewares | |
{ | |
/* | |
based on https://github.com/matthew-daddario/AspNetCoreRequestResponseLogger with some improvments. | |
# How To: | |
add midleware at startup.cs Configure method: | |
```c# | |
app.UseMiddleware<Middlewares.RequestResponseLoggingMiddleware>(); | |
``` | |
sample configs at appsettings.json: | |
```json | |
"Logging": { | |
"RequestResponseLogging": { | |
"Enabled": true, | |
"LogBodyEnabled": true | |
} | |
} | |
``` | |
*/ | |
public class RequestResponseLoggingMiddleware | |
{ | |
private readonly RequestDelegate _next; | |
private readonly bool _isEnabled; | |
private readonly bool _logBodyIsEnabled; | |
private readonly ILogger<RequestResponseLoggingMiddleware> _logger; | |
public RequestResponseLoggingMiddleware(RequestDelegate next, IConfiguration config, ILogger<RequestResponseLoggingMiddleware> logger) | |
{ | |
_next = next; | |
_logger = logger; | |
_isEnabled = config.GetValue<bool>("RequestResponseLogging.Enabled", true); | |
_logBodyIsEnabled = config.GetValue<bool>("RequestResponseLogging.LogBodyEnabled", true); | |
} | |
public async Task InvokeAsync(HttpContext httpContext) | |
{ | |
// Middleware is enabled only when the EnableRequestResponseLogging config value is set. | |
if (_isEnabled) | |
{ | |
_logger.LogInformation($"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" + | |
(_logBodyIsEnabled ? $"\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(); | |
_logger.LogInformation($"HTTP Response Information:\n" + | |
$"\tStatusCode: {httpContext.Response.StatusCode}\n" + | |
$"\tContentType: {httpContext.Response.ContentType}\n" + | |
$"\tHeaders: {FormatHeaders(httpContext.Response.Headers)}\n" + | |
(_logBodyIsEnabled ? $"\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; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment