MVC 表单无法发布对象列表

Posted

技术标签:

【中文标题】MVC 表单无法发布对象列表【英文标题】:MVC Form not able to post List of objects 【发布时间】:2013-11-26 16:33:48 【问题描述】:

所以我有一个有问题的 MVC Asp.net 应用程序。本质上,我有一个包含表单的视图,其内容绑定到对象列表。在这个循环中,它会加载 PartialView 以及被循环的项目。现在一切正常,直到提交表单。当它被提交时,控制器会收到一个空的对象列表。下面的代码说明了这些问题。

父视图:

@model IEnumerable<PlanCompareViewModel>
@using (html.BeginForm("ComparePlans", "Plans", FormMethod.Post, new  id = "compareForm" ))

<div>
    @foreach (var planVM in Model)
    
        @Html.Partial("_partialView", planVM)
    
</div>

_partialView:

@model PlanCompareViewModel
<div>
    @Html.HiddenFor(p => p.PlanID)
    @Html.HiddenFor(p => p.CurrentPlan)
    @Html.CheckBoxFor(p => p.ShouldCompare)
   <input type="submit" value="Compare"/>
</div>

这些是上面代码的类:

平面视图模型:

public class PlansCompareViewModel


    public int PlanID  get; set; 
    public Plan CurrentPlan  get; set; 
    public bool ShouldCompare  get; set; 
    public PlansCompareViewModel(Plan plan)
    
        ShouldCompare = false;
        PlanID = plan.PlanId;
        CurrentPlan = plan;
    

    public PlansCompareViewModel()
    
        // TODO: Complete member initialization
    
    public static IEnumerable<PlansCompareViewModel> CreatePlansVM(IEnumerable<Plan> plans)
    
        return plans.Select(p => new PlansCompareViewModel(p)).AsEnumerable();
    

控制器:

public class PlansController : MyBaseController

    [HttpPost]
    public ActionResult ComparePlans(IEnumerable<PlanCompareViewModel> model)
    
         //the model passed into here is NULL
    

问题出在控制器动作上。据我所知,它应该发布一个可枚举的 PlanCompareViewModels 列表,但它为空。在检查正在发送的发布数据时,它正在发送正确的参数。如果我将“IEnumerable”更改为“FormCollection”,它包含正确的值。谁能看到为什么活页夹没有创建正确的对象?我可以使用 javascript 解决这个问题,但这违背了目的!任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

您的模型是null,因为您向表单提供输入的方式意味着模型绑定器无法区分元素。现在,这段代码:

@foreach (var planVM in Model)

    @Html.Partial("_partialView", planVM)

没有为这些项目提供任何类型的索引。所以它会重复生成这样的 HTML 输出:

<input type="hidden" name="yourmodelprefix.PlanID" />
<input type="hidden" name="yourmodelprefix.CurrentPlan" />
<input type="checkbox" name="yourmodelprefix.ShouldCompare" />

但是,由于您要绑定到集合,您需要使用索引命名表单元素,例如:

<input type="hidden" name="yourmodelprefix[0].PlanID" />
<input type="hidden" name="yourmodelprefix[0].CurrentPlan" />
<input type="checkbox" name="yourmodelprefix[0].ShouldCompare" />
<input type="hidden" name="yourmodelprefix[1].PlanID" />
<input type="hidden" name="yourmodelprefix[1].CurrentPlan" />
<input type="checkbox" name="yourmodelprefix[1].ShouldCompare" />

该索引使模型绑定器能够关联单独的数据片段,从而构建正确的模型。所以这就是我建议你解决它的方法。与其使用局部视图循环遍历您的集合,不如利用模板的强大功能。以下是您需要遵循的步骤:

    在视图的当前文件夹内创建一个EditorTemplates 文件夹(例如,如果您的视图是Home\Index.cshtml,则创建文件夹Home\EditorTemplates)。 在该目录中创建一个名称与您的模型匹配的强类型视图。你的情况是PlanCompareViewModel.cshtml

现在,您在局部视图中的所有内容都希望进入该模板:

@model PlanCompareViewModel
<div>
    @Html.HiddenFor(p => p.PlanID)
    @Html.HiddenFor(p => p.CurrentPlan)
    @Html.CheckBoxFor(p => p.ShouldCompare)
   <input type="submit" value="Compare"/>
</div>

最后,你的父视图被简化为:

@model IEnumerable<PlanCompareViewModel>
@using (Html.BeginForm("ComparePlans", "Plans", FormMethod.Post, new  id = "compareForm" ))

<div>
    @Html.EditorForModel()
</div>

DisplayTemplatesEditorTemplates 足够聪明,可以知道他们何时处理集合。这意味着它们会自动为您的表单元素生成正确的名称,包括索引,以便您可以正确地建模绑定到集合。

【讨论】:

谢谢,今天这个答案真的帮到了我。【参考方案2】:

请阅读:http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx 您应该为您的 html 元素“名称”属性设置索引,例如 planCompareViewModel[0].PlanIdplanCompareViewModel[1].PlanId,以使 binder 能够将它们解析为 IEnumerable。 而不是 @foreach (var planVM in Model) 使用 for 循环并使用索引呈现名称。

【讨论】:

以上是关于MVC 表单无法发布对象列表的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 4 无法从表单中检索文件

对象集合的表单的 Freemarker 语法(Spring 3 MVC)

Spring MVC 动态列表表单提交

ASP.NET MVC 向最终用户显示操作成功

.net 5 MVC 多选列表不以多部分形式返回值

Spring MVC 和表单绑定:如何从列表中删除项目?