ASP.NET Core中视图向控制器传递ViewModel动态列表失败问题排查(库存编辑场景)
我之前也碰到过完全一样的坑!问题根源就在于你用foreach循环生成表单元素时,ASP.NET Core的模型绑定系统无法识别这些元素的命名规则——foreach不会自动生成带索引的name属性,而集合类型(比如List<LagerSaldoVM>)的模型绑定必须依赖明确的索引标识来关联每个输入项和集合中的元素。
下面是不用LINQ、只用基础循环的解决方案:
步骤1:调整视图的模型类型(或转换为可索引集合)
首先,把视图的模型从IEnumerable<LagerSaldoVM>改成List<LagerSaldoVM>(因为IEnumerable没有索引器,没法用for循环)。如果一定要保留IEnumerable,可以在视图里先转成List:
@model IEnumerable<LagerSaldoVM> @{ var saldoList = Model.ToList(); }
步骤2:用for循环替代foreach生成表单
把原来的foreach换成for循环,这样ASP.NET Core的标签助手会自动生成带索引的name属性(比如ls[0].Saldo、ls[1].Produkt),模型绑定器就能正确识别每个输入项属于集合中的哪一个元素。
另外必须添加Produkt的隐藏字段——原来的label只是显示文本,不会随表单提交,隐藏字段能把产品名称带回控制器,保证每个LagerSaldoVM的Produkt属性有值:
@model List<LagerSaldoVM> <body> <h1 class="rubrik">Ändra saldo för @ViewBag.Lager</h1> <div class="editBox"> <form method="post" asp-action="EditPost" asp-route-LagerID="@ViewBag.LagerID"> @for (int i = 0; i < Model.Count; i++) { <div class="form-group"> <!-- 隐藏字段:提交Produkt的值 --> <input type="hidden" asp-for="@Model[i].Produkt" /> <label asp-for="@Model[i].Produkt" class="control-label">@Model[i].Produkt</label> <input asp-for="@Model[i].Saldo" class="form-control" /> <span asp-validation-for="@Model[i].Saldo" class="text-danger"></span> </div> } <input type="submit" value="Uppdatera lager" class="update" /> </form> </div> </body>
步骤3:验证控制器的绑定逻辑
你的EditPost方法不需要修改,现在它的List<LagerSaldoVM> ls参数应该能正确接收到所有编辑后的库存数据了。可以在Debug里看到每个item.Saldo和item.Produkt都有对应的值。
为什么原来的foreach不行?
当你用foreach时,标签助手生成的name属性是类似item.Saldo的格式,模型绑定器不知道这个值属于集合中的哪一项。而for循环会生成ls[i].Saldo(ls是你Post方法的参数名,i是索引),这种命名规则正好符合ASP.NET Core集合绑定的要求,能让绑定器准确把每个输入值映射到List的对应元素上。
内容的提问来源于stack exchange,提问作者Ondrew

