ASP.NET Core 8 Web API:如何原生绑定含文件的复杂FormData对象
ASP.NET Core 8 Web API 原生处理包含文件与嵌套JSON对象的[FromForm]绑定方案
ASP.NET Core 8内置原生方案支持这类场景,无需自定义模型绑定,主要有两种实现方式:
方案1:使用嵌套键值对格式提交FormData(推荐,完全原生零后端改动)
默认的[FromForm]模型绑定器支持通过嵌套命名的键值对自动绑定复杂嵌套对象,只需调整前端FormData的构造逻辑,无需修改后端代码。
前端调整后的代码
const submit = () => { let form = new FormData(); // 直接以嵌套键名的形式append每个字段,对应后端的UploadedReviewDetailsDTO属性 form.append('review_details.rating_period_begin_date', ratingPeriodBeginModel.value!); form.append('review_details.rating_period_end_date', ratingPeriodEndModel.value!); form.append('review_details.document_title', documentTitleModel.value!); // 文件字段保持不变 form.append('document', documentModel.value); api.post('/DocumentReview', form, config).then(response => { // 处理响应逻辑 }); }
后端代码保持不变
[HttpPost("")] public async Task<IActionResult> AddDocumentReview([FromForm] UploadedDocumentReviewDTO documentReview) { return Ok(documentReview); } public class UploadedDocumentReviewDTO { [ModelBinder(Name = "review_details")] public required UploadedReviewDetailsDTO ReviewDetails { get; set; } [ModelBinder(Name = "document")] public required IFormFile Document { get; set; } } public class UploadedReviewDetailsDTO { public DateTime RatingPeriodBeginDate { get; set; } public DateTime RatingPeriodEndDate { get; set; } public string DocumentTitle { get; set; } = string.Empty; }
这种方式下,ASP.NET Core的默认模型绑定器会自动将review_details.xxx格式的键值对映射到UploadedReviewDetailsDTO的对应属性,同时支持数据注解验证(比如[Required]、[DataType]等),完全满足绑定阶段自动验证的需求。
方案2:保留JSON字符串提交,通过原生类型转换实现绑定
如果必须以JSON字符串的形式提交嵌套对象,可以通过自定义TypeConverter(.NET原生特性)实现自动反序列化,无需自定义模型绑定器。
步骤1:实现TypeConverter
using System.ComponentModel; using System.Text.Json; public class JsonStringToObjectConverter<T> : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) { return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } public override object? ConvertFrom(ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object value) { if (value is string jsonString) { return JsonSerializer.Deserialize<T>(jsonString, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); } return base.ConvertFrom(context, culture, value); } }
步骤2:在嵌套对象属性上注册TypeConverter
public class UploadedDocumentReviewDTO { [ModelBinder(Name = "review_details")] [TypeConverter(typeof(JsonStringToObjectConverter<UploadedReviewDetailsDTO>))] public required UploadedReviewDetailsDTO ReviewDetails { get; set; } [ModelBinder(Name = "document")] public required IFormFile Document { get; set; } }
前端代码保持不变
继续使用JSON.stringify将嵌套对象转为字符串后append到FormData中即可,后端会自动通过TypeConverter完成JSON字符串到对象的反序列化。
关于文件数组的原生支持
如果需要提交多个文件,后端只需将属性改为List<IFormFile>,前端多次append同一个字段名即可:
// 后端模型调整 public class UploadedDocumentReviewDTO { [ModelBinder(Name = "review_details")] public required UploadedReviewDetailsDTO ReviewDetails { get; set; } [ModelBinder(Name = "documents")] public required List<IFormFile> Documents { get; set; } }
// 前端代码 form.append('documents', file1); form.append('documents', file2); form.append('documents', file3);
默认模型绑定器会自动将所有同名的文件字段绑定到List<IFormFile>集合中。
内容的提问来源于stack exchange,提问作者Qiuzman
相关产品推荐
相关产品推荐

