C#如何从System.Mvc.Web.ActionExecutingContext获取全部请求体数据
问题描述
- 现有POST接口仅定义
long game单个入参,业务需求要求将用户提交的全部请求体内容存入日志,接口定义代码如下:
[HttpPost] [LogAPIUser] public async Task<JsonResult> GameDetail(long game)
- 使用Postman发起请求调试时,在
ActionExecutingContext中仅能获取到已定义的单个Action参数,无法拿到完整原始请求体 - 相关截图:
问题原因
ASP.NET Core的模型绑定流程会在Action执行前读取请求体流完成参数映射,默认请求体流是不支持重复读取的,读取完成后流指针会停在末尾,因此后续在过滤器中直接读取会得到空内容,只能拿到已经绑定完成的Action参数对象。
实现步骤
1. 开启请求体缓冲支持
首先需要在请求管道中开启请求体缓冲,允许请求流被多次读取,配置位置要放在路由、授权等中间件之前:
// Program.cs 中配置 var builder = WebApplication.CreateBuilder(args); // ... 其他服务配置 var app = builder.Build(); // 👇 加在这里,在所有用到请求体的中间件之前 app.Use(async (context, next) => { context.Request.EnableBuffering(); await next(); }); // ... 后续中间件配置 app.UseRouting()、app.UseAuthorization() 等
2. 在日志过滤器中读取原始请求体
修改LogAPIUser过滤器的逻辑,读取请求体前先将流指针重置到起始位置,读取完成后再复位指针,避免影响后续模型绑定流程:
using System.Text; using Microsoft.AspNetCore.Mvc.Filters; public class LogAPIUserAttribute : Attribute, IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var request = context.HttpContext.Request; // 仅处理带请求体的POST请求,可按需加PUT等其他方法 if (request.Method == HttpMethods.Post) { // 重置流指针到起始位置 request.Body.Position = 0; // 读取全部请求体内容,注意leaveOpen参数要设为true,不要释放请求流 using var reader = new StreamReader( request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: 1024, leaveOpen: true); string rawRequestBody = await reader.ReadToEndAsync(); // 此处即可拿到完整原始请求体,执行日志存储逻辑 // 例如:_logger.LogInformation("接口请求体:{Body}", rawRequestBody); // 读取完成后再次复位指针,保证后续模型绑定正常执行 request.Body.Position = 0; } // 继续执行后续Action流程 await next(); } }
注意事项
- 如果接口涉及大文件上传场景,不建议直接读取全量请求体到内存,会额外占用服务器资源,普通JSON/表单类接口使用该方案无问题
- 必须配置
EnableBuffering(),否则直接设置request.Body.Position会抛出流不支持Seek的异常 - 读取请求体时必须将
StreamReader的leaveOpen参数设为true,否则请求流会被释放,导致后续模型绑定失败
内容的提问来源于stack exchange,提问作者Chmn
相关产品推荐
相关产品推荐



