使用Tuple作为视图模型时,提交表单后控制器Action中List对象为空的问题求助
使用Tuple作为视图模型时,提交表单后控制器Action中List对象为空的问题求助
嗨,我来帮你排查这个问题!你的核心问题出在Tuple的只读特性和模型绑定的字段名不匹配这两点上,咱们一步步来解决:
为什么你的代码没拿到数据?
- Tuple的属性是只读的:ASP.NET Core的模型绑定需要对象有可写入的属性(带
set方法),但传统Tuple的Item1、Item2都是只读的,绑定器没法把表单提交的值赋值进去。 - 字段名和Action参数不匹配:你手动设置了表单输入框的
name为Item1[{i}].Level1,但控制器Action的参数是List<CompanyPricingLevels> levels,模型绑定会找名为levels的字段,自然匹配不上,导致levels为空。
最佳解决方案:自定义ViewModel
Tuple虽然方便,但不适合做MVC的视图模型,最好创建一个专门的视图模型类,这样既清晰又能完美支持模型绑定:
1. 创建自定义ViewModel类
public class CompanyPricingViewModel { // 对应原来Tuple的Item1 public List<CompanyPricingLevels> PricingLevels { get; set; } // 对应原来Tuple的Item2 public CompanyModuleDetails ModuleDetails { get; set; } }
2. 修改视图代码
把模型类型换成自定义的ViewModel,同时移除手动设置的@Name(让TextBoxFor自动生成正确的绑定字段名):
@model CompanyPricingViewModel @if (Model.ModuleDetails.Module.ModuleName == "Consolidation") { <div class="container"> <h1>Company Pricing Levels</h1> @using (Html.BeginForm("SaveLevels", "Admin", FormMethod.Post)) { <table class="table"> <thead> <tr> <th>Level Type</th> <th>Level 1</th> <th>Level 2</th> <th>Level 3</th> <th>Level 4</th> <th>Level 5</th> <th>Level 6</th> </tr> </thead> <tbody> @for (int i = 0; i < Model.PricingLevels.Count; i++) { <tr> <td>@Model.PricingLevels[i].LevelType</td> <td>@Html.TextBoxFor(model => model.PricingLevels[i].Level1, new { @class = "form-control" })</td> <td>@Html.TextBoxFor(model => model.PricingLevels[i].Level2, new { @class = "form-control" })</td> <td>@Html.TextBoxFor(model => model.PricingLevels[i].Level3, new { @class = "form-control" })</td> <td>@Html.TextBoxFor(model => model.PricingLevels[i].Level4, new { @class = "form-control" })</td> <td>@Html.TextBoxFor(model => model.PricingLevels[i].Level5, new { @class = "form-control" })</td> <td>@Html.TextBoxFor(model => model.PricingLevels[i].Level6, new { @class = "form-control" })</td> </tr> } </tbody> </table> <button type="submit" class="btn btn-primary">Save</button> } </div> }
3. 修改控制器Action
现在可以直接接收自定义的ViewModel,轻松拿到提交的列表数据:
[HttpPost] public IActionResult SaveLevels(CompanyPricingViewModel model) { // 这里用model.PricingLevels就能获取到提交的所有定价级别数据了 // 后续可以做保存逻辑 return View(); }
备选方案(不推荐,但可以临时解决)
如果你不想创建ViewModel,也可以调整Action参数名和表单字段名匹配:
- 把Action参数名改成
Item1:public IActionResult SaveLevels(List<CompanyPricingLevels> Item1) - 同时移除视图里手动设置的
@Name,让TextBoxFor生成Item1[{i}].LevelX的字段名,这样模型绑定就能匹配上。不过这种方式可读性差,还是推荐自定义ViewModel。
备注:内容来源于stack exchange,提问作者MarkBerry
相关产品推荐
相关产品推荐

