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

ASP.NET Core MVC中如何将视图数据回传至控制器?

ASP.NET Core MVC动态列表回传控制器解决方案

核心问题根源

ASP.NET Core的模型绑定对集合类型的表单元素有严格的格式要求:表单元素的name属性必须遵循[索引].属性名或父模型属性[索引].属性名的格式。你动态添加行时如果没正确设置name,控制器就无法识别并绑定集合;另外AJAX的请求头、参数序列化方式也可能导致绑定失败。


具体修复步骤

1. 规范动态行的name属性格式

部分视图(单条ChildViewModel行)

用带索引的格式生成表单元素的name,确保模型绑定能识别:

@model ChildViewModel
<div class="child-row">
    <input type="text" name="[@Model.Index].Name" value="@Model.Name" placeholder="姓名" />
    <input type="number" name="[@Model.Index].Age" value="@Model.Age" placeholder="年龄" />
    <button type="button" class="remove-row">删除</button>
</div>

这里的Index是每个行的唯一序号,动态添加时需依次递增。

动态添加行的脚本

维护一个计数器确保索引连续唯一,通过AJAX加载部分视图:

// 初始索引为已有列表的行数
let rowIndex = @Model.ChildViewModels.Count;

$('#add-row-btn').click(function() {
    $.get('/Home/GetChildRow', { index: rowIndex }, function(html) {
        $('#child-list-container').append(html);
        rowIndex++;
    });
});

控制器返回部分视图的动作

public IActionResult GetChildRow(int index)
{
    return PartialView("_ChildRow", new ChildViewModel { Index = index });
}

2. 修正AJAX提交逻辑

两种可行的提交方式:

方式一:表单序列化(推荐)

直接序列化整个表单,自动收集所有带正确name的元素:

$('#submit-btn').click(function() {
    const formData = $('#main-form').serialize();
    
    $.ajax({
        url: '/Home/SaveChildren',
        type: 'POST',
        data: formData,
        contentType: 'application/x-www-form-urlencoded; charset=UTF-8', // 必须设置这个
        success: function(res) {
            alert('保存成功');
        },
        error: function(xhr) {
            console.error(xhr.responseText);
        }
    });
});

对应的控制器动作(如果用父模型包裹集合):

public class ParentViewModel
{
    public List<ChildViewModel> ChildViewModels { get; set; } = new List<ChildViewModel>();
}

[HttpPost]
public IActionResult SaveChildren(ParentViewModel model)
{
    // model.ChildViewModels就是回传的集合
    // 执行保存逻辑
    return Ok();
}

此时部分视图的name要改为ChildViewModels[@Model.Index].Name,和父模型的集合属性对应。

方式二:JSON序列化提交

手动构建JSON数组,适合不需要整个表单的场景:

$('#submit-btn').click(function() {
    const children = [];
    $('.child-row').each(function() {
        const $row = $(this);
        children.push({
            Name: $row.find('input[name$=".Name"]').val(),
            Age: parseInt($row.find('input[name$=".Age"]').val())
        });
    });
    
    $.ajax({
        url: '/Home/SaveChildren',
        type: 'POST',
        data: JSON.stringify(children),
        contentType: 'application/json; charset=UTF-8',
        success: function(res) {
            alert('保存成功');
        }
    });
});

控制器动作需要加[FromBody]特性:

[HttpPost]
public IActionResult SaveChildren([FromBody] List<ChildViewModel> childViewModels)
{
    // 处理保存逻辑
    return Ok();
}

3. 确保视图模型属性可绑定

视图模型的属性必须是公共可读写属性,不能是字段:

public class ChildViewModel
{
    public int Index { get; set; } // 用于生成索引,可选但方便动态行生成
    public string Name { get; set; }
    public int Age { get; set; }
    // 其他业务属性
}

常见错误排查

  1. 打开浏览器开发者工具的网络面板,查看请求的Form Data/Request Payload,确认所有行的数据都已正确提交,格式符合要求。
  2. 检查控制器动作的参数名称与提交的集合名称是否匹配(比如父模型的集合属性是ChildViewModels,表单元素name必须以ChildViewModels开头)。
  3. 动态添加行时不要重复使用相同索引,否则后面的行数据会覆盖前面的。

优化建议

  1. 用ASP.NET Core的TagHelper生成表单元素,自动处理name属性,比如:<input asp-for="ChildViewModels[index].Name" />,避免手动拼写错误。
  2. 复杂动态表单场景,建议用Vue.js、React等前端框架管理数据模型,提交时直接序列化模型即可,减少手动处理DOM的繁琐。
  3. 可以为动态行添加删除逻辑时,重新整理索引(非必须,但能保证索引连续),避免因删除行导致索引断档(模型绑定支持非连续索引,但连续索引更稳妥)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:35:18