I am working on Asp.Net Core API, There are around 1000 endpoints which can have different bodies (request payload). I want to log the the incoming requests for each endpoint. I dont want to go and make changes in each endpoint. So Is there a way to do this?
I have tried the below. But it logs requestBody as empty string. Although I get the request object value in the controller action method. The below code is for http post.
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Log the request details
_logger.LogInformation($"Request: {context.HttpContext.Request.Method} {context.HttpContext.Request.Path}");
// Log the request body for POST requests
if (context.HttpContext.Request.Method.Equals("POST", StringComparison.OrdinalIgnoreCase))
{
context.HttpContext.Request.EnableBuffering();
// Read the request body
using (var reader = new StreamReader(context.HttpContext.Request.Body, encoding: Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true))
{
var requestBody = await reader.ReadToEndAsync();
// Reset the position of the request body stream
context.HttpContext.Request.Body.Position = 0;
_logger.LogInformation($"Request Body: {requestBody}");
}
}
// Call the action method
var resultContext = await next();
// Perform any post-action execution logic if needed
}
I have tried this and this is working for one endpoint, but there could be many different request types so I'll end up using multiple if else and I want to avoid it, basically I'm looking for a generic solution.
https://stackoverflow.com/a/67262551/6527049
Note : I have read some articles mentioning that it can be done using middleware, but in this question I'm more interested in fixing issue in my code. Or can be fixed using ActionFilter
First of all I highly recommend to look into using existing HTTP Logging infrastructure provided by the framework , note that you can enable it conditionally with UseWhen
(like it is done here or here ).
If for some reason it is not sutable for you then for your problem:
But it logs requestBody as empty string
There are 2 possible problems here (do not have setup to repro ATM):
EnableBuffering
is called too late, try adding next middleware somewhere at the start of the pipeline (like it is done here ): app.Use((context, next) =>
{
context.Request.EnableBuffering();
return next();
});
// ...
// ...
context.HttpContext.Request.Body.Position = 0;
using (var reader = new StreamReader(context.HttpContext.Request.Body, encoding: Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true))
{
var requestBody = await reader.ReadToEndAsync();
// Reset the position of the request body stream
context.HttpContext.Request.Body.Position = 0;
_logger.LogInformation($"Request Body: {requestBody}");
}
Also check out this answer .
I tested your code, and it seems to work well. Do you send your request as JSON with the body? Could you please verify the Content-Type header?
Here is your code with minor modifications.
class ActionFilterExample:
public class ActionFilterExample : IAsyncActionFilter
{
private readonly ILogger _logger;
public ActionFilterExample(ILogger logger)
{
_logger = logger;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Log the request details
_logger.LogInformation($"Request: {context.HttpContext.Request.Method} {context.HttpContext.Request.Path}");
// Log the request body for POST requests
if (context.HttpContext.Request.Method.Equals("POST", StringComparison.OrdinalIgnoreCase))
{
context.HttpContext.Request.EnableBuffering();
// seek
context.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
// Read the request body
using var reader = new StreamReader(context.HttpContext.Request.Body,
encoding: Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: 8192,
leaveOpen: true);
var requestBody = await reader.ReadToEndAsync();
// Reset the position of the request body stream
context.HttpContext.Request.Body.Position = 0;
_logger.LogInformation($"Request Body: {requestBody}");
}
// Call the action method
var resultContext = await next();
// Perform any post-action execution logic if needed
}
inside program.cs
ILogger logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
builder.Services.AddControllersWithViews(config =>
{
config.Filters.Add(new ActionFilterExample(logger));
});
Use the built in middleware that takes things like sensitive information in requests and performance into consideration (not buffering the entire request body into memory as a string to log).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.