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

如何复用微软[FromForm]逻辑实现IFormCollection转模型(含数组)

自定义InputFormatter表单数组映射解决方案

问题背景

我实现了一个自定义InputFormatter,可通过HttpContext.Request.Form处理表单数据,能完成简单模型映射,但无法处理数组类型。而原生[FromForm]特性支持多种数组形式的表单数据格式,比如当Action接收Foo列表时,模型定义如下:

public class Foo
{
    public Bar[] Bar { get; set; }
}

public class Bar
{
    public string Blah { get; set; }
}

以下表单Key格式均被原生[FromForm]支持:

  • [foo][0][bar][0][blah]
  • [0][bar][0][blah]
  • foo[0].bar[0].blah
  • [0].bar[0].blah

我希望自定义InputFormatter也支持上述所有场景,理想方案是复用微软在[FromForm]中把IFormCollection转换为目标模型的逻辑,最好能有类似JSON/XML处理器的表单输入处理能力。

实现方案

复用原生模型绑定逻辑

ASP.NET Core中[FromForm]的模型绑定逻辑由FormCollectionModelBinder及相关组件实现,直接调用这套逻辑即可实现需求:

  1. 注入核心依赖
    在自定义InputFormatter的构造函数中注入IModelBinderFactory和IModelMetadataProvider:
private readonly IModelBinderFactory _modelBinderFactory;
private readonly IModelMetadataProvider _modelMetadataProvider;

public CustomFormInputFormatter(IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider)
{
    _modelBinderFactory = modelBinderFactory;
    _modelMetadataProvider = modelMetadataProvider;
    // 添加自定义支持的媒体类型,可根据需求调整
    SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/custom-form"));
}
  1. 重写请求体读取方法
    在方法内构建模型绑定上下文,调用原生绑定逻辑完成解析:
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
    var httpContext = context.HttpContext;
    var formCollection = await httpContext.Request.ReadFormAsync();
    
    // 获取目标模型元数据并创建绑定器
    var modelMetadata = _modelMetadataProvider.GetMetadataForType(context.ModelType);
    var modelBinder = _modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
    {
        Metadata = modelMetadata,
        BindingInfo = new BindingInfo()
    });
    
    // 构建模型绑定上下文
    var bindingContext = new DefaultModelBindingContext
    {
        ModelMetadata = modelMetadata,
        ModelName = context.ModelName,
        ValueProvider = new FormValueProvider(BindingSource.Form, formCollection, CultureInfo.CurrentCulture),
        ActionContext = new ActionContext(httpContext, new RouteData(), new ControllerActionDescriptor()),
        ModelState = context.ModelState
    };
    
    // 执行原生模型绑定
    await modelBinder.BindModelAsync(bindingContext);
    
    return bindingContext.Result.IsModelSet 
        ? InputFormatterResult.Success(bindingContext.Result.Model) 
        : InputFormatterResult.NoValue();
}

注册自定义格式化器

在Program.cs中将自定义InputFormatter添加到MVC配置:

builder.Services.AddControllers(options =>
{
    var serviceProvider = builder.Services.BuildServiceProvider();
    options.InputFormatters.Insert(0, new CustomFormInputFormatter(
        serviceProvider.GetRequiredService<IModelBinderFactory>(),
        serviceProvider.GetRequiredService<IModelMetadataProvider>()
    ));
});

通过以上实现,自定义InputFormatter将完全复用原生[FromForm]的所有数组解析逻辑,支持所有合法的表单Key格式。

内容的提问来源于stack exchange,提问作者JED

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 14:45:06