简体   繁体   English

模型内的列表项在发布后始终为空-Asp.net MVC

[英]List item inside model always null on post - Asp.net MVC

I am trying to post model which contains List<> item looks like below: 我正在尝试发布包含List <>项目的模型,如下所示:

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; }
}

I am populating all required fields on get method and feeding List from database 我在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);
}

And my view code looks like below : 我的视图代码如下所示:

@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"/>
}

On View, the list items rendered properly and even I am able to edit those fields. 在View上,列表项正确呈现,甚至我也可以编辑这些字段。
But On post, all properties have the value except AllFeatures list item property which always shows count = 0. 但是在发布时,所有属性都具有除AllFeatures列表项属性以外的值,该属性始终显示count = 0。

Edit 1: This is how my view looks like while rendering features 编辑1:这是渲染功能时我的视图的样子

在此处输入图片说明

Edit 2: 编辑2:

Signature of the method posting to: 该方法的签名发布到:

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

But On post, all properties have the value except AllFeatures list item property which always shows count = 0. 但是在发布时,所有属性都具有除AllFeatures列表项属性以外的值,该属性始终显示count = 0。

AllFeatures is a generic list of Feature . AllFeaturesFeature的通用列表。 When you do this: 执行此操作时:

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

The Razor view engine will render this: 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. -->

In other words, HiddenFor calls the ToString() on the item and simply puts that into the input tag's value attribute. 换句话说, HiddenFor调用项目上的ToString()并将其简单地放入input标签的value属性中。

What happens upon POST 开机自检后会发生什么

When you post the form, the DefaultModelBinder is looking for a property named AllFeatures but of type string so it can assign this to it: 发布表单时, DefaultModelBinder正在寻找一个名为AllFeatures的属性,但其类型为string因此可以将其分配给它:

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

It does not find one since your model does not have AllFeatures of type string , so it simply ignores it and binds all the other properties. 它没有找到一个,因为你的模型没有AllFeatures类型的string ,所以它简单地忽略它,并结合所有其他属性。

AllFeatures list item property which always shows count = 0. AllFeatures列表项属性,始终显示count = 0。

Yes, it will and this is not the AllFeatures list which you posted but the one from the constructor which clearly is an empty list with a count 0: 是的,它不是您发布的AllFeatures列表,而是构造函数中的一个列表,它显然是一个空列表,计数为0:

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

I am not sure why you are sending all the features to the client (browser) and then you need to post it back to the server. 我不确定为什么要将所有功能发送到客户端(浏览器),然后将其重新发布到服务器。

Solution

To fix the issue, simply remove this line: 要解决此问题,只需删除以下行:

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

Now it will not cause any confusion during binding and MVC will bind the items in the loop to the AllFeatures property. 现在,在绑定过程中不会引起任何混乱,MVC会将循环中的项目绑定到AllFeatures属性。

In fact, the only code you really need, as far as I can tell from your question is this(I could be wrong if you need the hidden fields for some other reason. But if you just want the user to edit the AllFeatures, you do not need any of the hidden fields): 实际上,据我所知,您真正需要的唯一代码是(如果出于其他原因需要隐藏字段,我可能是错误的。但是,如果您只希望用户编辑AllFeature,不需要任何隐藏字段):

@for (int i = 0; i < Model.AllFeatures.Count; i++)
{
    <tr>
        <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>
}

I think your issue might be the nested property. 我认为您的问题可能是嵌套属性。 You may want to review the posted form and see what it looks like. 您可能需要查看已发布的表单,并查看其外观。

Your markup looks correct assuming that the model binding would work for a nested property - which I am not sure it does. 假设模型绑定适用于嵌套属性,那么您的标记看起来正确,但我不确定这样做是否正确。 (Just to make sure I searched for and found this old Haack post that indicates you're doing it right: Haack Post ) (只是确保我搜索并发现了这条旧的Haack帖子,它表明您做对了: Haack Post

As a workaround (and POC), you can try the following: Add a new parameter to your action for your features, post it like your doing now but not nested (so you can't use the Model For HTML helpers) and then in the controller, you can set it back to your main object's features property. 作为一种解决方法(和POC),您可以尝试以下操作:在功能操作中添加新参数,像现在那样发布但不嵌套(因此您不能使用Model For HTML helper),然后在控制器,您可以将其设置回主对象的features属性。

This how to do it, as in the context of binding to a list from a view is incorrect. 这样做的方法,例如从视图绑定到列表的上下文中,是不正确的。

View: 视图:

@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>

Controller: 控制器:

[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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM