ASP.NET Core自定义InputFormatter调用时请求体已被消耗问题
ASP.NET Core自定义InputFormatter时请求体被提前消耗的问题
我尝试在ASP.NET Core中创建自定义InputFormatter,因为框架没有处理application/x-www-form-urlencoded内容的默认格式化程序。但当我的格式化程序被调用时,请求体流已被消耗——通过中间件可验证请求体在管道早期存在,但不清楚被谁消耗。
根据《模型绑定》文档:
输入格式化程序全权负责从请求体读取数据。
但实际情况是请求体已无内容可读取。
我的代码与官方自定义输入格式化程序示例非常相似:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Formatters; using System.Text; using System.Text.Json.Nodes; namespace slim { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(options => { options.InputFormatters.Add(new FormUrlEncodedInputFormatter()); }); var app = builder.Build(); app.MapControllers(); // Uncomment this to see the expected body content "name=value" is present // app.Use(async (c, next) => // { // Console.WriteLine(await new StreamReader(c.Request.Body).ReadToEndAsync()); // await next(c); // }); app.Run(); } } [ApiController] public class EchoController : ControllerBase { [Route("/echo")] public ActionResult Echo([FromBody] JsonObject obj) => Ok(obj); } public class FormUrlEncodedInputFormatter : TextInputFormatter { public FormUrlEncodedInputFormatter() { SupportedMediaTypes.Add("application/x-www-form-urlencoded"); SupportedEncodings.Add(Encoding.UTF8); } protected override bool CanReadType(Type type) => type == typeof(JsonObject); public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) { // PROBLEM: str is always empty ("") var str = await new StreamReader(context.HttpContext.Request.Body).ReadToEndAsync(); var d = str.Split('&').Where(s => s.Length > 0).Select(s => s.Split('=')) .ToDictionary(kv => kv[0], kv => kv[1]); return InputFormatterResult.Success(d); } } }
我通过PowerShell调用接口:
Invoke-RestMethod "http://localhost:5186/echo" -Method POST -Body @{ name="value" }
作为临时解决方案,我可以启用请求缓冲,让格式化程序倒回流,但按文档要求这不应是必需的:
app.Use(async (context, next) => { if (context.Request.ContentType == "application/x-www-form-urlencoded") { context.Request.EnableBuffering(); } await next(context); });
我哪里操作有误?
更新:我发现使用[FromForm]属性可接收form-urlencoded内容,它并非实际的InputFormatter,无需显式注册contentType。可能是使[FromForm]生效的机制在我的格式化程序之前消耗了请求体。将Echo方法参数的[FromBody]替换为[FromForm]并移除自定义格式化程序注册后,示例可正常运行。
内容的提问来源于stack exchange,提问作者Bob Meyers
相关产品推荐
相关产品推荐

