如何复用微软[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及相关组件实现,直接调用这套逻辑即可实现需求:
- 注入核心依赖
在自定义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")); }
- 重写请求体读取方法
在方法内构建模型绑定上下文,调用原生绑定逻辑完成解析:
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
相关产品推荐
相关产品推荐

