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

FormData已赋值但后端接口接收为null,移除CompanyTargets相关代码后恢复正常的排查与解决

FormData已赋值但后端接口接收为null,移除CompanyTargets相关代码后恢复正常的排查与解决

你遇到的这个问题,我之前在做ASP.NET Core的FormData提交时也碰到过,大概率是嵌套集合的模型绑定规则没满足导致的,结合你的代码,我整理了几个最可能的原因和对应的解决办法:

一、核心原因:CompanyTargets的集合索引不连续,导致模型绑定失败

你的代码里用了companies数组的全局索引cIndex来生成CompanyTargets[${cIndex}]的键名,但如果不是每个company都满足colName.includes(companyName)的匹配条件,就会出现索引跳号的情况(比如cIndex是0、1、2,但只匹配了0和2,FormData里就会有CompanyTargets[0]和CompanyTargets[2],中间的1缺失)。

而ASP.NET Core的FromForm模型绑定,对集合的索引有个默认要求:必须是从0开始的连续整数,一旦出现跳号,绑定器就无法正确识别整个集合,甚至会直接导致父级的Item乃至整个vm绑定失败(变成null)。

解决办法:给每个Item的CompanyTargets用独立的局部索引

把原来的cIndex换成每个Item自己的局部索引,只有匹配成功时才递增,保证索引连续:

// 在tRows.forEach((row) => { ... })内部,处理columns的逻辑之前,先定义局部索引
let targetIndex = 0; // 每个Item的CompanyTargets从0开始计数

// 然后修改companies循环的代码:
companies.forEach((company) => {
    const companyName = company.CompanyName.toLowerCase().replace(/\s+/g, '');
    if (colName.includes(companyName)) {  
        // 用targetIndex代替cIndex
        formData.append(`vm.Items[${itemIndex}].CompanyTargets[${targetIndex}].CompanyID`, company.CompanyID.toString()); 
        formData.append(`vm.Items[${itemIndex}].CompanyTargets[${targetIndex}].ItemID`, itemID.toString()); // 显式转字符串,避免类型问题

        if (configuration.IsOngoing && configuration.KRAEnabled) {
            if (colName.toLowerCase().includes("-tgt")) {
                formData.append(`vm.Items[${itemIndex}].CompanyTargets[${targetIndex}].Target`, data.textContent.trim() || "");
            } 
        } else if (configuration.IsOngoing && configuration.AppraisalEnabled) {
            if (colName.toLowerCase().includes("-rst")) {
                formData.append(`vm.Items[${itemIndex}].CompanyTargets[${targetIndex}].Result`, data.textContent.trim() || "");
            }
        }
        targetIndex++; // 只有匹配成功才递增,保证索引连续
    }
});

二、次要排查点:数据类型不匹配,导致绑定中断

除了索引问题,还要核对前后端的属性类型是否一致:

  1. 后端CompanyTargetViewModel里的CompanyID、ItemID是int还是string?
    • 如果后端是int,前端要传数字格式的字符串(比如company.CompanyID.toString()),别直接传数字(虽然FormData会自动转,但显式处理更稳妥);
    • 如果后端是Guid,前端要传完整的Guid字符串(比如company.CompanyID本身是Guid的话,直接转字符串即可)。
  2. 确认ItemID是有效的数字:你的代码里itemID是parseInt(row.getAttribute("data-bd-item-id")) || 0,转成字符串后再append,避免潜在的类型转换异常。

三、额外检查:后端ViewModel的集合结构是否正确

确保你的后端PerformanceViewerViewModel的嵌套结构完全符合FormData的提交格式:

  1. Items集合的每个元素里,CompanyTargets必须是可实例化的集合类型(比如List<CompanyTargetViewModel>,不能是IEnumerable<CompanyTargetViewModel>或者自定义的非标准集合);
  2. CompanyTargetViewModel必须有公共无参构造函数,并且所有需要绑定的属性都是get; set;的可读写状态。

比如后端模型应该类似:

public class PerformanceViewerViewModel
{
    public List<GoalViewModel> Goals { get; set; }
    public List<ItemViewModel> Items { get; set; }
}

public class ItemViewModel
{
    // 其他属性:TempItemID、GoalID、ItemID等
    public List<CompanyTargetViewModel> CompanyTargets { get; set; }
}

public class CompanyTargetViewModel
{
    public int CompanyID { get; set; }
    public int ItemID { get; set; }
    public string Target { get; set; }
    public string Result { get; set; }
}

四、临时排查技巧:查看浏览器请求的FormData内容

打开浏览器开发者工具的Network面板,找到你的POST请求,查看Form Data的具体内容:

  • 检查CompanyTargets的键名索引是否连续(比如vm.Items[0].CompanyTargets[0]、vm.Items[0].CompanyTargets[1],没有跳号);
  • 检查值的格式是否符合后端要求(比如数字是否是纯字符串,没有多余符号)。

按照上面的步骤修改后,应该就能解决后端vm为null的问题了。

备注:内容来源于stack exchange,提问作者mat mat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 13:54:31