ASP.NET Core 2.2中InvalidModelStateResponseFactory读取请求体为空问题
解决InvalidModelStateResponseFactory中请求体为空的问题
这个问题我之前也遇到过——在InvalidModelStateResponseFactory里读请求体总是空,核心原因是模型绑定阶段已经提前读取过请求体流了,流的指针停在了末尾,哪怕你调用了EnableRewind,不重置指针位置的话还是读不到内容。下面给你两种可行的解决方案:
方案1:在工厂内直接重置流位置
直接修改你的InvalidModelStateResponseFactory代码,在启用流重读后手动将指针重置到起始处:
public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.Configure<ApiBehaviorOptions>(options => { options.InvalidModelStateResponseFactory = actionContext => { var request = actionContext.HttpContext.Request; // 启用流的重读支持(允许修改指针位置) request.EnableRewind(); // 关键步骤:将流指针重置到起始位置 request.Body.Position = 0; using(StreamReader stream = new StreamReader(request.Body)) { string body = stream.ReadToEnd(); // 这里可以用body做日志记录、错误分析等操作 // 可选:读完后重置指针,避免影响后续可能的中间件(如果有的话) request.Body.Position = 0; } return new BadRequestObjectResult(new { Message = "模型验证失败", Errors = actionContext.ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage)) }); }; }); }
方案2:全局配置请求体可重读(更稳妥)
如果你的应用其他地方也需要重读请求体,可以在全局中间件里提前配置流缓冲,这样模型绑定后流依然可以被重置读取:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // 把这个中间件放在最前面(UseMvc之前) app.Use(async (context, next) => { // 启用流缓冲,让整个请求生命周期内都能重读请求体 context.Request.EnableRewind(); await next(); }); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } app.UseHttpsRedirection(); app.UseMvc(); }
配置完全局中间件后,在InvalidModelStateResponseFactory里只需要重置流位置就能读取请求体,不用每次都调用EnableRewind。
为什么之前的代码无效?
ASP.NET Core的模型绑定系统会在进入InvalidModelStateResponseFactory之前,就已经读取了请求体流来绑定Action的参数,此时流的Position已经到了末尾。EnableRewind只是让流支持Seek操作(也就是可以修改指针位置),但不会自动把指针重置到开头,所以必须手动设置request.Body.Position = 0才能重新读取内容。
内容的提问来源于stack exchange,提问作者dev-masih
相关产品推荐
相关产品推荐

