【问题标题】:MVC using IEnumerable<Model> with Razor is null after post to controller使用带有 Razor 的 IEnumerable<Model> 的 MVC 在发布到控制器后为空
【发布时间】:2018-05-13 20:08:39
【问题描述】:

我的模特

public class ActivityModel
{
    public int Id { get; set; }
    public String Nick { get; set; }
    public String TripName { get; set; }
    [DisplayFormat(DataFormatString = "{0:hh\\:mm}", ApplyFormatInEditMode = true)]
    public TimeSpan? FromTime { get; set; }
    [DisplayFormat(DataFormatString = "{0:hh\\:mm}", ApplyFormatInEditMode = true)]
    public TimeSpan? ToTime { get; set; }
    public String FromPlace { get; set; }
    public String ToPlace { get; set; }
    public String activityType { get; set; }
    [DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}", ApplyFormatInEditMode = true)]
    public DateTime? Timestamp { get; set; }
    public String Weather { get; set; }
    public int Difficulty { get; set; }
    public bool Reviewed { get; set; }
}

我的视图行看起来像这样

@model IList<ActivityModel>
    @for (int i = 0; i < Model.Count; i++)
{
    if (!(bool)Model[i].Reviewed)
    {
        <tr>
            @using (Html.BeginForm("Accept", "Overview", FormMethod.Post, new { activityModel = Model }))
            {
                @Html.AntiForgeryToken()
                <td>
                    @Html.DisplayFor(m => Model[i].Timestamp)
                    @Html.HiddenFor(m => Model[i].Timestamp)
                </td>
                <td>
                    @Html.DisplayFor(m => Model[i].Nick)
                    @Html.HiddenFor(m => Model[i].Nick)
                </td>
                <td>
                    @Html.DisplayFor(m => Model[i].TripName)
                    @Html.HiddenFor(m => Model[i].TripName)
                </td>
                <td>
                    @Html.DisplayFor(m => Model[i].FromTime)
                    @Html.HiddenFor(m => Model[i].FromTime)
                </td>
                <td>
                    @Html.DisplayFor(m => Model[i].FromPlace)
                    @Html.HiddenFor(m => Model[i].FromPlace)
                </td>
                <td>
                    @Html.DisplayFor(m => Model[i].ToTime)
                    @Html.HiddenFor(m => Model[i].ToTime)
                </td>
                <td>
                    @Html.DisplayFor(m => Model[i].ToPlace)
                    @Html.HiddenFor(m => Model[i].ToPlace)
                </td>
                <td>
                    @Html.TextBoxFor(m => Model[i].Difficulty, new { id = "Difficulty" })
                    <--!@Html.HiddenFor(m => Model[i].Difficulty)--!>
                    <div style="visibility:hidden">
                        @Html.HiddenFor(m => Model[i].Id)
                        @Html.HiddenFor(m => Model[i].Reviewed)
                        @Html.HiddenFor(m => Model[i].activityType)
                        @Html.HiddenFor(m => Model[i].Weather)
                    </div>
                </td>
                <td>
                    <input type="submit" name="btn_accept" value="Accept" />
                </td>
            }
        </tr>
     }
}

我的控制器是这个

public ActionResult Index()
{
    List<ActivityModel> activities_web = new List<ActivityModel>();    
    //someLogicForFilling
    return View(activities_web);
}

[HttpPost]
[ValidateAntiForgeryToken()]
public ActionResult Accept(ActivityModel activityModel)
{
    return RedirectToAction("Index");
}

问题是在 ActionResult Accept 中 ActivityModel 总是 NULL 空 0 ... 我现在真的花了一整天的时间,我不知道问题出在哪里我尝试了近 20 种解决方案,但对我没有任何效果..

渲染页面并显示所有值是可以的,但是当我尝试发布它们时,就像没有发布一样。

【问题讨论】:

    标签: post model-view-controller model


    【解决方案1】:

    当发布的数据与您用作 HttpPost 操作方法参数的类的属性结构匹配时,模型绑定将起作用。

    您当前的视图代码正在生成这样的 HTML 代码

    <input name="[0].Id" type="hidden" value="101">
    <input name="[1].Id" type="hidden" value="202">
    

    假设您在要传递给视图的集合中有 2 个项目。

    可以看到name属性值为[0].Id[1].Id。但是您的 Accept 操作方法的参数是单个 ActivityModel 对象,属性名称类似于 IdFromPlace 等。要使模型绑定起作用,您的输入名称和属性名称应该匹配。

    您可以重写您的视图代码,为您的隐藏输入生成正确的name 属性值。您可以简单地使用纯 HTML 代码来创建隐藏输入并从模型项中设置值或使用 Html.HiddenFor 辅助方法。

    @foreach (var item in Model.Where(a => a.Reviewed == false))
    {
        <input type="hidden" name="FromPlace" value="@item.FromPlace" />
        @Html.Hidden("ToPlace", item.ToPlace)
        @Html.Hidden(nameof(ActivityModel.Id), item.Id)
    }
    

    这是完整的代码(为了节省空间,排除了一些属性)。

    @model IList<ActivityModel>
    <table class="table table-striped">
        @foreach (var item in Model.Where(a => a.Reviewed == false))
        {
            using (Html.BeginForm("Accept", "Process", FormMethod.Post))
            {                   
                @Html.AntiForgeryToken()
                <tr>
                    <td>
                        @Html.DisplayFor(m => item.FromPlace)
                        @Html.Hidden("FromPlace", item.FromPlace)
                    </td>
                    <td>
                        @Html.DisplayFor(m => item.ToPlace)
                        @Html.Hidden("ToPlace", item.ToPlace)
                    </td>
                    <td>
                        @Html.Hidden(nameof(ActivityModel.Id),item.Id)
                        <input type="submit" name="btn_accept" value="Accept" />
                    </td>
                </tr>
            }
        }
    </table>
    

    但理想情况下,如果您尝试更新单个实体/记录的状态,您只需要该记录的Id(主键)即可。这意味着,您确实不需要填充所有属性。在这种情况下,您需要 Id 属性值的隐藏输入元素。如果需要,您始终可以使用此Id 查询数据库以获取完整实体。 (永远不要相信来自客户端的数据)

    【讨论】:

    • 是的,就是这样,名称创建不正确,但为什么如果我使用助手,我认为它会正确创建它..如果他们这样做名称不匹配,为什么要使用它们?跨度>
    • 因为您是在循环中创建的。它创建的名称是正确的,如果您想将模型绑定到 ActivityModel 列表(例如,如果您想对一堆记录进行编辑并将它们一起提交。您将使用 List&lt;ActivityModel&gt; 作为您的http post action 方法参数和模型绑定可以正常工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-22
    相关资源
    最近更新 更多