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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 01:02:17