【问题标题】:List item inside model always null on post - Asp.net MVC模型内的列表项在发布时始终为空 - Asp.net MVC
【发布时间】:2017-07-08 17:35:51
【问题描述】:

我正在尝试发布包含 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; }
}

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

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:这是我的视图在渲染功能时的样子

编辑 2:

方法的签名发布到:

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

【问题讨论】:

  • 你能给我们一段为循环生成的最终 HTML。我想对于同一属性的隐藏字段和编辑器字段的组合,它可能很难映射一个强类型的对象。
  • 为什么需要将AllFeatures 发送到浏览器,然后再将其发回服务器?
  • 用户将能够编辑视图中的所有功能并回发@CodingYoshi
  • @TravisActon 我试图保留所有属性中的值。我尝试了 hidden for 和 EditFor,但都未能将值从视图保存到控制器。
  • 是的,但是在您在此处发布的视图中,您对同一模型属性使用了 editfor 和 hiddenfor。删除 hiddenfor 看看会发生什么,我想当你有重复的属性时尝试自动绑定可能会遇到问题。

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


【解决方案1】:

但在发布时,所有属性都具有除 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 类型的string,所以它只是忽略它并绑定所有其他属性。

AllFeatures 列表项属性始终显示 count = 0。

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

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

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

解决方案

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

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

现在它不会在绑定过程中造成任何混乱,并且 MVC 会将循环中的项目绑定到 AllFeatures 属性。

事实上,据我所知,您真正需要的唯一代码是这个(如果您出于其他原因需要隐藏字段,我可能是错的。但如果您只是希望用户编辑AllFeatures,您不需要任何隐藏字段):

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

【讨论】:

  • 用户将能够编辑视图中的所有功能并回发
  • @VigneshwaranMarkandan 好的!我可以查看您发布到的操作的签名吗?
  • 当然。 [HttpPost] 公共 ActionResult 映射(AddSubscriptionPlanModel 模型){ }。我为您编辑了帖子,请检查。
【解决方案2】:

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

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

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

【讨论】:

  • 那篇文章谈到了将模型列表 作为参数传递。您所说的解决方法将是上述问题的替代方案,而不是解决方案。
  • 是的,这是真的:)
【解决方案3】:

这是怎么做的,因为在从视图绑定到列表的上下文中是不正确的。

查看:

@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

【讨论】:

  • 如果我有模型,为什么还需要 FormCollection?
  • 我研究了很久,无法绑定AllFeatures,因为它是一个集合。我可以将下拉列表显示为集合,用户可以选择一个,但我无法按照您想要的方式绑定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-29
  • 2017-02-15
  • 1970-01-01
  • 2017-10-29
  • 2020-09-18
  • 2018-03-20
相关资源
最近更新 更多