模型内的列表项在post-Asp.net MVC上始终为null

时间:2017-07-08 17:35:52

标签: c# asp.net asp.net-mvc-4 razor

我正在尝试发布包含列表<> 项目的模型,如下所示:

public class AddSubscriptionPlanModel
{
    public AddSubscriptionPlanModel()
    {
        AllFeatures = new List<Feature>();
    }
    public int Id { get; set; }
    public int SubscriptionPlanId { get; set; }
    public int SubscriptionId { get; set; }
    public string Name { get; set; }
    public bool IsActive { get; set; }
    [Display(Name = "No Of Users")]
    public int? NoOfUsers { get; set; }
    [Display(Name = "Duration Type")]
    public DurationType DurationType { get; set; }
    public int Duration { get; set; }
    public decimal Amount { get; set; }
    public int SubscriptionPlanTrailId { get; set; }
    public int FeatureId { get; set; }
    public DateTime CreatedDateUtc { get; set; }
    public DateTime LastUpdatedUtc { get; set; }
    public int CreatedBy { get; set; }
    public int LastUpdatedBy { get; set; }    
    public List<Feature> AllFeatures { get; set; }
}

我在get方法中填充所有必填字段并从数据库中提供List

public ActionResult Mapping(int id)
{        
    var features = FeatureManager.GetAllFeatures();
    var model = new Ejyle.DevAccelerate.Web.App.Models.SubscriptionPlan.AddSubscriptionPlanModel();

    model.AllFeatures = features;
    model.Id = id;
    model.SubscriptionId = id;
    model.NoOfUsers = 20;
    model.SubscriptionPlanId = 1;
    model.SubscriptionPlanTrailId = 1;
    model.Amount = 1000;
    model.CreatedBy = 1;
    model.LastUpdatedBy = 1;
    model.FeatureId = 1;
    model.Duration = 20;

    return View(model);
}

我的观看代码如下所示:

@using (Html.BeginForm("Mapping", "SubscriptionPlans", FormMethod.Post))
{
    @Html.HiddenFor(model => model.Id)
    @Html.HiddenFor(model => model.Amount)
    @Html.HiddenFor(model => model.Duration)
    @Html.HiddenFor(model => model.FeatureId)
    @Html.HiddenFor(model => model.CreatedBy)
    @Html.HiddenFor(model => model.LastUpdatedBy)
    @Html.HiddenFor(model => model.NoOfUsers)
    @Html.HiddenFor(model => model.SubscriptionId)
    @Html.HiddenFor(model => model.SubscriptionPlanId)
    @Html.HiddenFor(model => model.SubscriptionPlanTrailId)
    @Html.HiddenFor(model => model.AllFeatures)
    <table class="table table-striped">
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Name)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.IsActive)
                </th>
            </tr>
        </thead>
        <tbody>
            @for (int i=0; i < Model.AllFeatures.Count; i++)
            {
                <tr>
                    @Html.HiddenFor(model => model.AllFeatures[i].Id)
                    @Html.HiddenFor(model => model.AllFeatures[i].Name)
                    @Html.HiddenFor(model => model.AllFeatures[i].IsActive)
                    <td>
                        @Html.TextBoxFor(model => model.AllFeatures[i].Id)
                    </td>
                    <td>
                        @Html.TextBoxFor(model => model.AllFeatures[i].Name)
                    </td>
                    <td>
                        @Html.EditorFor(model => model.AllFeatures[i].IsActive)
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <input type="submit" class="btn btn-success" value="Submit" name="Submit"/>
}

在“视图”上,列表项正确呈现,甚至我可以编辑这些字段 但是在帖子中,所有属性都具有除 AllFeatures 列表项属性之外的值,该属性始终显示count = 0。

编辑1:这是渲染功能时我的视图的样子

enter image description here

编辑2:

发布方法的签名:

[HttpPost]
public ActionResult Mapping(AddSubscriptionPlanModel model)
{       
}

3 个答案:

答案 0 :(得分:3)

  

但是在帖子上,所有属性都具有除AllFeatures列表项属性之外的值,该属性始终显示count = 0。

AllFeaturesFeature的通用列表。当你这样做时:

@Html.HiddenFor(model => model.AllFeatures) 

Razor视图引擎将呈现:

<input id="AllFeatures" 
       name="AllFeatures" 
       type="hidden" 
       value="System.Collections.Generic.List`1[Namespace.Feature]">
       <!--Where Namespace is the Namespace where Feature is defined. -->

换句话说,HiddenFor会调用该项目的ToString(),只需将其放入input代码的value属性中。

POST后会发生什么

当您发布表单时,DefaultModelBinder正在查找名为AllFeatures但属于string的属性,以便将其分配给它:

System.Collections.Generic.List`1[Namespace.Feature]

由于您的模型没有类型AllFeatures的{​​{1}},所以找不到它,因此它只是忽略它并绑定所有其他属性。

  

AllFeatures列出项属性,它始终显示count = 0。

是的,它会,这不是您发布的string列表,而是来自构造函数的列表,它显然是一个带有计数0的空列表:

AllFeatures

我不确定您为什么要将所有功能发送到客户端(浏览器),然后您需要将其发回服务器。

<强>解决方案

要解决此问题,只需删除此行:

public AddSubscriptionPlanModel()
{
    AllFeatures = new List<Feature>();
}

现在它不会在绑定期间造成任何混淆,MVC会将循环中的项绑定到@Html.HiddenFor(model => model.AllFeatures) 属性。

事实上,你真正需要的唯一代码,就我从你的问题中可以看出的那样(如果你因为其他原因需要隐藏字段,我可能会错。但如果你只是想让用户编辑AllFeatures,您不需要任何隐藏字段):

AllFeatures

答案 1 :(得分:1)

我认为您的问题可能是嵌套属性。您可能需要查看已发布的表单并查看其外观。

假设模型绑定适用于嵌套属性,您的标记看起来是正确的 - 我不确定它是什么。 (只是为了确保我搜索并找到了这个旧的Haack帖子,表明你做得对:Haack Post

作为一种变通方法(和POC),您可以尝试以下操作:为您的功能添加一个新参数,将其发布为您现在正在执行但不是嵌套(因此您无法使用Model For HTML帮助程序)然后在控制器中,您可以将其设置回主对象的features属性。

答案 2 :(得分:1)

如何在视图中绑定到列表的上下文中这样做是不正确的。

查看:

@model Testy20161006.Controllers.AddSubscriptionPlanModel
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Mapping</title>
</head>
<body>
    @*I am using controller home*@
    @using (Html.BeginForm("Mapping", "Home", FormMethod.Post))
    {
        @Html.HiddenFor(model => model.Id)
        @Html.HiddenFor(model => model.Amount)
        @Html.HiddenFor(model => model.Duration)
        @Html.HiddenFor(model => model.FeatureId)
        @Html.HiddenFor(model => model.CreatedBy)
        @Html.HiddenFor(model => model.LastUpdatedBy)
        @Html.HiddenFor(model => model.NoOfUsers)
        @Html.HiddenFor(model => model.SubscriptionId)
        @Html.HiddenFor(model => model.SubscriptionPlanId)
        @Html.HiddenFor(model => model.SubscriptionPlanTrailId)
        @Html.HiddenFor(model => model.AllFeatures)
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>
                        @Html.DisplayNameFor(model => model.Name)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.IsActive)
                    </th>
                </tr>
            </thead>
            <tbody>
                @for (int i = 0; i < Model.AllFeatures.Count; i++)
                {
                    <tr>
                        @*BE SURE to get rid of these*@
                        @*@Html.HiddenFor(model => model.AllFeatures[i].Id)
                            @Html.HiddenFor(model => model.AllFeatures[i].Name)
                            @Html.HiddenFor(model => model.AllFeatures[i].IsActive)*@
                        <td>
                            @Html.TextBoxFor(model => model.AllFeatures[i].Id)
                        </td>
                        <td>
                            @Html.TextBoxFor(model => model.AllFeatures[i].Name)
                        </td>
                        <td>
                            @Html.EditorFor(model => model.AllFeatures[i].IsActive)
                        </td>
                    </tr>
                }
            </tbody>
        </table>
        <input type="submit" class="btn btn-success" value="Submit" name="Submit" />
    }
</body>
</html>

控制器:

[HttpPost]
public ActionResult Mapping(AddSubscriptionPlanModel addSubscriptionModel, FormCollection formCollection)
    {
        var AllFeatures = String.Empty;
        var index = "AllFeatures[";
        foreach (var item in formCollection)
        {
            if (item.ToString().Contains(index))
            {
                AllFeatures += " " + formCollection.GetValues(item.ToString())[0];
            }
        }

        //put breakpoint here to see userValues