You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 11:03:36