Razor Pages foreach内textarea提交OnPost时IEnumerable对象为Null
问题根因
你的代码存在4个直接导致模型绑定失败的问题:
- 集合属性类型不支持绑定:你定义的
ExpendituresList是IEnumerable<Expenditure>类型,ASP.NET Core 集合模型绑定需要可按索引读写的集合类型(如List<T>),IEnumerable本身不支持索引写入操作,绑定器无法完成值填充。 - 表单字段命名不符合绑定规则:ASP.NET Core 绑定集合时,要求表单字段的
name属性必须遵循[集合属性名].[索引].[字段名]的格式。你使用foreach循环+FirstOrDefault()LINQ查询给asp-for赋值的写法,生成的textarea、隐藏域的name属性完全不满足该规则,绑定器无法识别字段和集合项的对应关系。 - 漏写表单标签:你的表格和提交按钮没有包裹在
method="post"的<form>标签内,默认情况下表单控件的值不会被提交到后端。 - 隐藏域绑定错误:你写的
@Html.HiddenFor(model => expenditure.ExpenditureItemId)生成的隐藏域name为expenditure.ExpenditureItemId,和目标集合属性ExpendituresList没有关联,提交后后端无法获取每个条目的主键值。
修复方案
1. 调整后端集合属性类型
将IEnumerable<Expenditure>改为List<Expenditure>,保证绑定器可以正常操作集合:
[BindProperty(SupportsGet = true)] public List<Expenditure> ExpendituresList { get; set; } = new();
如果你的OnGet方法中是通过LINQ查询给该属性赋值,只需要在查询末尾加.ToList()即可,不需要修改原有查询逻辑。
2. 重写CSHTML页面代码
核心修改点:
- 所有需要提交的内容包裹在post表单内
- 用带索引的for循环替代foreach循环,直接通过索引访问集合项生成
asp-for绑定,禁止在asp-for中使用LINQ查询方法 - 按索引生成主键隐藏域,额外添加索引标记隐藏域兼容非连续索引场景
修改后的完整代码:
@model WorkInProgress.Pages.Expenditures <form method="post"> <table class="table"> <thead> <tr> <th class="text-start">Task Number</th> <th class="text-start">Expenditure Type</th> <th class="text-end">Item Date</th> <th class="text-end">Billable</th> <th class="text-end">Vendor Id</th> <th></th> <th class="text-start">Vendor Name</th> <th class="text-end">Revenue Amount</th> <th class="text-end">Comments</th> </tr> </thead> <tbody> @for (var i = 0; i < Model.ExpendituresList.Count; i++) { <tr> <td class="text-start">@Model.ExpendituresList[i].TaskNumber</td> <td class="text-start">@Model.ExpendituresList[i].ExpenditureType</td> <td class="text-end">@Model.ExpendituresList[i].ExpenditureItemDate.ToString("dd-MMM-yyyy")</td> <td class="text-end">@Model.ExpendituresList[i].BillableFlag</td> <td class="text-end">@Model.ExpendituresList[i].VendorId</td> <td></td> <td class="text-start">@Model.ExpendituresList[i].SupplierName</td> <td class="text-end">@Model.ExpendituresList[i].ProjFuncRevenueAmount</td> @* 集合索引标记,兼容非连续索引场景 *@ <input type="hidden" asp-for="ExpendituresList[i].Index" value="@i" /> @* 主键隐藏域,按索引绑定 *@ <input type="hidden" asp-for="ExpendituresList[i].ExpenditureItemId" /> <td class="text-end"> <textarea class="form-control" asp-for="ExpendituresList[i].ExpenditureComment" rows="1"></textarea> </td> </tr> } </tbody> </table> <div class="p-3"> <button type="submit" class="btn btn-primary" asp-page-handler="Button">Save</button> </div> </form>
3. 后端Post方法无需额外修改
绑定器会自动将提交的表单值填充到ExpendituresList属性中,你直接在OnPostButton方法中访问该属性即可获取所有行的备注和对应主键:
public IActionResult OnPostButton() { // 此处ExpendituresList已完成绑定,可直接遍历处理保存逻辑 foreach (var item in ExpendituresList) { var itemId = item.ExpenditureItemId; var comment = item.ExpenditureComment; // 你的业务保存逻辑 } return RedirectToPage(); }
绑定原理说明
asp-for标签 helper在for循环中按索引生成的字段name属性格式为ExpendituresList[0].ExpenditureComment、ExpendituresList[0].ExpenditureItemId、ExpendituresList[1].ExpenditureComment,完全匹配ASP.NET Core集合模型绑定的命名约定,绑定器会自动按索引将表单值映射到集合对应项,不会出现空值问题。
注意:永远不要在循环中使用FirstOrDefault、Where等LINQ方法为asp-for赋值,这类写法生成的name属性无法被集合绑定器识别。
内容的提问来源于stack exchange,提问作者Baldie47
相关产品推荐
相关产品推荐

