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

ASP.NET Core Razor Page表单如何提交关联实体数据?

问题核心原因

ASP.NET Core Razor Pages 的复杂集合模型绑定要求表单字段的name属性严格遵循约定格式,动态生成的产品输入项未符合该约定,因此无法被服务端正确接收。

具体解决方案

1. 明确绑定规则

要绑定List<ProductModel> Products属性,每个产品的输入字段name必须满足以下两种格式之一:

  • 连续索引格式:Products[N].属性名,其中N是从0开始的连续整数,适合无删除行需求的场景
  • 自定义索引格式:每行增加隐藏的Products.Index字段,索引可以是任意不重复值(支持数字、字符串、时间戳等),适合需要删除行的场景,无需调整其他行的索引

2. 前端表单实现示例

基础表格结构

<form method="post" id="invoiceForm">
  <!-- 发票基础字段 -->
  <div>
    <label>发票名称</label>
    <input asp-for="Invoice.Name" />
  </div>
  <div>
    <label>发票描述</label>
    <input asp-for="Invoice.Description" />
  </div>

  <!-- 产品表格 -->
  <table id="productTable">
    <thead>
      <tr>
        <th>产品名称</th>
        <th>型号</th>
        <th>品牌</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <!-- 初始产品行,对应索引0 -->
      <tr>
        <td><input name="Invoice.Products[0].Name" /></td>
        <td><input name="Invoice.Products[0].Model" /></td>
        <td><input name="Invoice.Products[0].Brand" /></td>
        <td><button type="button" class="delete-row">删除</button></td>
      </tr>
    </tbody>
  </table>

  <button type="button" id="addProduct">新增产品</button>
  <button type="submit">提交</button>
</form>

注:如果你的PageModel中直接把InvoiceModel作为绑定属性,字段前缀要和属性名对应,比如绑定属性名为Invoice就加Invoice.前缀,如果是直接绑定List<ProductModel> Products则不需要前缀

动态新增行JS逻辑(使用自定义索引方案,支持删除)

// 用时间戳作为索引,避免重复
document.getElementById('addProduct').addEventListener('click', function() {
  const index = Date.now();
  const newRow = `
    <tr>
      <input type="hidden" name="Invoice.Products.Index" value="${index}" />
      <td><input name="Invoice.Products[${index}].Name" /></td>
      <td><input name="Invoice.Products[${index}].Model" /></td>
      <td><input name="Invoice.Products[${index}].Brand" /></td>
      <td><button type="button" class="delete-row">删除</button></td>
    </tr>
  `;
  document.querySelector('#productTable tbody').insertAdjacentHTML('beforeend', newRow);

  // 如果使用了jQuery Unobtrusive验证,需要重新解析验证规则
  // $.validator.unobtrusive.parse('#invoiceForm');
});

// 删除行逻辑
document.querySelector('#productTable tbody').addEventListener('click', function(e) {
  if (e.target.classList.contains('delete-row')) {
    e.target.closest('tr').remove();
  }
});

3. 后端PageModel配置

确保后端绑定属性标记了[BindProperty]:

public class CreateInvoiceModel : PageModel
{
    [BindProperty]
    public InvoiceModel Invoice { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (ModelState.IsValid)
        {
            // Invoice.Products 已经自动绑定了所有提交的产品数据
            // 你的业务逻辑
            return RedirectToPage("Index");
        }
        return Page();
    }
}

常见排查点

  • 检查动态生成的input的name属性拼写是否和模型属性完全一致
  • 如果使用连续索引方案,确保删除行后索引保持连续,否则会出现后面的行绑定失败的问题
  • 嵌套层级严格对应,比如如果模型是Invoice.Products,name属性不能少了Invoice.前缀

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 13:24:03