I have a middleware, where I catch the errors and I want to print the route and the information sent in the body, I use several displayed codes but the information returned is empty.
this is the middleware I use to catch errors that may occur in my source code, what I do is catch the error and print the stack.
using System.Net.Mime;
using System.Net;
using System.Transactions;
using System.Text;
using Microsoft.AspNetCore.Http;
namespace MyWebApi.Middlewares
{
public static class MyCustomMiddlewareExtensions
{
public static IApplicationBuilder UseMyCustomMiddleware(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyCustomMiddleware>();
}
}
public class MyCustomMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<MyCustomMiddleware> _logger;
public MyCustomMiddleware(RequestDelegate next, ILogger<MyCustomMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
if (context.Response.StatusCode == (int)HttpStatusCode.Unauthorized)
throw new UnauthorizedAccessException();
}
catch (Exception ex)
{
_logger.LogError("({errorCode})Message Error: {ex}\r\nqueryString/Body:{queryString}", "500", ex, await GetInfo(context));
}
}
private async Task<string> GetInfo(HttpContext context)
{
var request = context.Request;
string result = string.Empty;
if (request.Method == HttpMethods.Post && request.ContentLength > 0)
{
request.EnableBuffering();
request.Body.Position = 0;
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
await request.BodyReader.ReadAsync();
//get body string here...
var requestContent = Encoding.UTF8.GetString(buffer);
request.Body.Position = 0;
result = string.Concat('[', request.Method, "]: ", request.Path, '/', request.QueryString, "\r\nBody: ", requestContent);
}
else
{
result = string.Concat('[', request.Method, "]: ", request.Path, '/', request.QueryString);
}
return result;
}
}
}
Program.cs:
var app = builder.Build();
//Middlewares
app.UseMyCustomMiddleware();
in my controller:
namespace MyWebApi.Controllers.V4
{
[ApiController]
[EnableCors("cors")]
[Authorize]
[Route("v{version:apiVersion}/Products")]
[ApiVersion("4.0")]
public class ProductsController : Controller
{
private readonly IConfiguration _configuration;
private readonly IproductsBusinessLogic _productsBusinessLogic;
private readonly IValidator<ProductsRequestDto> _ProductsRequestDtoValidator;
private readonly ILogger<ProductsController> _logger;
public ProductsController(
ILogger<ProductsController> logger,
IConfiguration configuration,
IproductsBusinessLogic productsBusinessLogic,
IValidator<ProductsRequestDto> ProductsRequestDtoValidator
)
{
_logger = logger;
_configuration = configuration;
_productsBusinessLogic = productsBusinessLogic;
_ProductsRequestDtoValidator = ProductsRequestDtoValidator;
}
[MapToApiVersion("4.0")]
[HttpPost]
public async Task<IActionResult> Register([FromBody] ProductsRequestDto request)
{
var results = await _ProductsRequestDtoValidator.ValidateAsync(request);
results.AddToModelState(ModelState, null);
if (!results.IsValid)
{
return new ValidationFailedResult(results);
}
var result = await _productsBusinessLogic.Register(request);
return Ok(result);
}
}
}
in the log is printed out:
queryString/Body:[POST]: /v4.0/Products/ Body: |
I found the solution in https://medium.com/@luisalexandre.rodrigues/logging-http-request-and-response-in-net-web-api-268135dcb27b
Create below middleware and call it in program.cs/startup class.
app.UseMiddleware<RequestResponseLoggerMiddlware>();
private readonly RequestDelegate _next;
private readonly ILogger<LoggingMiddleware> _logger;
public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
await LogRequest(context);
var originalResponseBody = context.Response.Body;
using (var responseBody = new MemoryStream())
{
context.Response.Body = responseBody;
await _next.Invoke(context);
await LogResponse(context, responseBody, originalResponseBody);
}
}
private async Task LogResponse(HttpContext context, MemoryStream responseBody, Stream originalResponseBody)
{
var responseContent = new StringBuilder();
responseContent.AppendLine("=== Response Info ===");
responseContent.AppendLine("-- headers");
foreach (var (headerKey, headerValue) in context.Response.Headers)
{
responseContent.AppendLine($"header = {headerKey} value = {headerValue}");
}
responseContent.AppendLine("-- body");
responseBody.Position = 0;
var content = await new StreamReader(responseBody).ReadToEndAsync();
responseContent.AppendLine($"body = {content}");
responseBody.Position = 0;
await responseBody.CopyToAsync(originalResponseBody);
context.Response.Body = originalResponseBody;
_logger.LogInformation(responseContent.ToString());
}
private async Task LogRequest(HttpContext context)
{
var requestContent = new StringBuilder();
requestContent.AppendLine("=== Request Info ===");
requestContent.AppendLine($"method = {context.Request.Method.ToUpper()}");
requestContent.AppendLine($"path = {context.Request.Path}");
requestContent.AppendLine("-- headers");
foreach (var (headerKey, headerValue) in context.Request.Headers)
{
requestContent.AppendLine($"header = {headerKey} value = {headerValue}");
}
requestContent.AppendLine("-- body");
context.Request.EnableBuffering();
var requestReader = new StreamReader(context.Request.Body);
var content = await requestReader.ReadToEndAsync();
requestContent.AppendLine($"body = {content}");
_logger.LogInformation(requestContent.ToString());
context.Request.Body.Position = 0;
}
}