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

ASP.NET Core中通过jQuery Ajax传递含表格数据的表单至控制器问题

问题解决方案

核心原因

ASP.NET Core的模型绑定规则比传统MVC更严格,尤其对集合类型的命名格式、请求内容类型的要求更明确,你遇到的表格数据为null的问题,大概率是表单字段命名不符合绑定规则或Ajax请求的序列化/内容类型配置错误导致的。

分步修复

1. 确保ViewModel集合属性初始化

在主ViewModel中初始化集合属性,避免绑定时空引用:

public class UserFormViewModel
{
    public string UserName { get; set; }
    public string Department { get; set; }
    // 初始化集合,防止绑定后为null
    public List<DealerHistoryViewModel> DealerHistories { get; set; } = new List<DealerHistoryViewModel>();
}

public class DealerHistoryViewModel
{
    public string DealerName { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
}

2. 修正视图中表格字段的name属性

表格行的表单元素name必须严格遵循 集合属性名[索引].子属性名 的格式,且索引必须连续(0,1,2...),不能断号:

<form id="userForm">
    <!-- 普通表单字段 -->
    <input type="text" name="UserName" placeholder="用户名" />
    <select name="Department">
        <option value="销售部">销售部</option>
        <option value="市场部">市场部</option>
    </select>

    <!-- 经销商历史表格 -->
    <table id="dealerTable">
        <thead>
            <tr>
                <th>经销商名称</th>
                <th>开始日期</th>
                <th>结束日期</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <!-- 初始行,索引从0开始 -->
            <tr>
                <td><input type="text" name="DealerHistories[0].DealerName" /></td>
                <td><input type="date" name="DealerHistories[0].StartDate" /></td>
                <td><input type="date" name="DealerHistories[0].EndDate" /></td>
                <td><button type="button" class="removeRow">删除</button></td>
            </tr>
        </tbody>
    </table>
    <button type="button" id="addRow">添加行</button>
    <button type="button" id="submitForm">提交</button>
</form>

3. 修正添加/删除行的脚本逻辑

添加行时要生成连续的索引,删除行后必须重新整理所有行的索引,避免断号导致模型绑定失败:

// 添加新行
$('#addRow').click(function() {
    var rowCount = $('#dealerTable tbody tr').length;
    var newRow = `
    <tr>
        <td><input type="text" name="DealerHistories[${rowCount}].DealerName" /></td>
        <td><input type="date" name="DealerHistories[${rowCount}].StartDate" /></td>
        <td><input type="date" name="DealerHistories[${rowCount}].EndDate" /></td>
        <td><button type="button" class="removeRow">删除</button></td>
    </tr>`;
    $('#dealerTable tbody').append(newRow);
});

// 删除行并重设索引
$(document).on('click', '.removeRow', function() {
    $(this).closest('tr').remove();
    // 重新设置所有行的索引
    $('#dealerTable tbody tr').each(function(index) {
        $(this).find('input[name^="DealerHistories"]').each(function() {
            var newName = $(this).attr('name').replace(/\[(\d+)\]/, `[${index}]`);
            $(this).attr('name', newName);
        });
    });
});

4. 修正Ajax请求与控制器配置

根据数据传递方式选择对应配置:

方式一:表单编码格式(推荐,和传统MVC逻辑一致)

直接用serialize()序列化表单,控制器参数标记[FromForm]:

$('#submitForm').click(function(e) {
    e.preventDefault();
    var formData = $('#userForm').serialize();
    $.ajax({
        url: '/User/SaveUser',
        type: 'POST',
        data: formData,
        success: function(res) {
            console.log('提交成功');
        },
        error: function(xhr) {
            console.error('提交失败');
        }
    });
});

控制器代码:

[HttpPost]
public IActionResult SaveUser([FromForm] UserFormViewModel model)
{
    if (ModelState.IsValid)
    {
        // 处理业务逻辑
        return Ok("保存成功");
    }
    return BadRequest(ModelState);
}

方式二:JSON格式传递

如果需要用JSON传递,需手动构建包含数组的JSON对象,控制器参数标记[FromBody]:

$('#submitForm').click(function(e) {
    e.preventDefault();
    // 构建表单数据对象
    var formData = {
        UserName: $('input[name="UserName"]').val(),
        Department: $('select[name="Department"]').val(),
        DealerHistories: []
    };
    // 收集表格数据
    $('#dealerTable tbody tr').each(function() {
        formData.DealerHistories.push({
            DealerName: $(this).find('input[name$=".DealerName"]').val(),
            StartDate: $(this).find('input[name$=".StartDate"]').val(),
            EndDate: $(this).find('input[name$=".EndDate"]').val()
        });
    });
    $.ajax({
        url: '/User/SaveUser',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify(formData),
        success: function(res) {
            console.log('提交成功');
        },
        error: function(xhr) {
            console.error('提交失败');
        }
    });
});

控制器代码:

[HttpPost]
public IActionResult SaveUser([FromBody] UserFormViewModel model)
{
    if (ModelState.IsValid)
    {
        // 处理业务逻辑
        return Ok("保存成功");
    }
    return BadRequest(ModelState);
}

常见错误排查点

  • 表格字段name格式错误:比如写成DealerName[0]而不是DealerHistories[0].DealerName
  • 索引断号:删除行后未重新整理索引,导致绑定跳过后续行
  • 请求contentType不匹配:用了JSON序列化但没设置contentType: 'application/json',或表单编码格式却用了[FromBody]
  • ViewModel集合未初始化:未给DealerHistories赋值新的List,导致绑定后仍为null

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 08:38:12