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

求助:通过Ajax向.NET Core 8传递含IFormFile的自定义类时列表为空

问题排查与解决:.NET Core 8中[FromForm]接收列表属性为空的问题

核心原因分析

列表属性无法绑定的本质是前端FormData的键名格式不匹配.NET模型绑定规则,常见触发场景包括:

  • 未使用索引下标/空括号标识集合元素,直接用PreventivoArticoloDettaglioDS.Nome这种格式传递,模型绑定器无法识别为列表项
  • 前端键名与后端实体类属性名大小写/拼写不一致(.NET默认模型绑定区分大小写)
  • 直接将整个列表对象添加到FormData,而非逐个遍历添加子属性

解决方法

1. 前端FormData的正确构造方式

必须通过索引下标明确标识列表中的每个子项,以下是示例代码:

const formData = new FormData();

// 添加主对象普通属性
formData.append("Id", "1001");
formData.append("Titolo", "客户报价单");
// 添加文件
formData.append("Allegato", document.getElementById("fileInput").files[0]);

// 遍历并添加PreventivoArticoloDettaglioDS列表项
const articoliList = [
    { codice: "ART001", qta: 5, prezzo: 20.5 },
    { codice: "ART002", qta: 2, prezzo: 150.0 }
];
articoliList.forEach((item, index) => {
    formData.append(`PreventivoArticoloDettaglioDS[${index}].CodiceArticolo`, item.codice);
    formData.append(`PreventivoArticoloDettaglioDS[${index}].Quantita`, item.qta);
    formData.append(`PreventivoArticoloDettaglioDS[${index}].PrezzoUnitario`, item.prezzo);
});

// 遍历并添加PreventivoPagamentoDS列表项
const pagamentiList = [
    { tipo: "首付", percentuale: 30 },
    { tipo: "尾款", percentuale: 70 }
];
pagamentiList.forEach((item, index) => {
    formData.append(`PreventivoPagamentoDS[${index}].TipoPagamento`, item.tipo);
    formData.append(`PreventivoPagamentoDS[${index}].Percentuale`, item.percentuale);
});

// Ajax请求配置(必须禁用processData和contentType)
$.ajax({
    url: "/Preventivo/Save",
    type: "POST",
    data: formData,
    processData: false, // 禁止jQuery自动处理FormData
    contentType: false, // 让浏览器自动设置正确的Content-Type
    success: res => console.log("提交成功")
});

2. 后端实体与控制器的校验

确保实体类属性为可公共访问并包含get/set方法,控制器参数正确标记[FromForm]:

public class PreventivoDS
{
    public int Id { get; set; }
    public string Titolo { get; set; }
    public IFormFile Allegato { get; set; }
    public List<PreventivoArticoloDettaglioDS> PreventivoArticoloDettaglioDS { get; set; }
    public List<PreventivoPagamentoDS> PreventivoPagamentoDS { get; set; }
}

public class PreventivoArticoloDettaglioDS
{
    public string CodiceArticolo { get; set; }
    public int Quantita { get; set; }
    public decimal PrezzoUnitario { get; set; }
}

public class PreventivoPagamentoDS
{
    public string TipoPagamento { get; set; }
    public int Percentuale { get; set; }
}

// 控制器方法
[HttpPost]
public IActionResult Save([FromForm] PreventivoDS model)
{
    // 处理业务逻辑
    return Ok(model);
}

3. 额外排查点

  • 打开浏览器开发者工具的Network标签,检查FormData的键名是否与后端属性完全匹配(包括列表索引格式)
  • 若子对象包含嵌套列表,需递归构造键名,例如PreventivoArticoloDettaglioDS[0].SottoArticoli[0].Nome
  • 如需兼容大小写不敏感绑定,可在Program.cs中配置:
builder.Services.AddControllersWithViews()
    .AddMvcOptions(options =>
    {
        options.ModelBinderProviders.Insert(0, new CaseInsensitiveModelBinderProvider());
    });

(注:CaseInsensitiveModelBinderProvider需自定义实现,或优先保持前后端属性名大小写一致)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 10:17:17