【问题标题】:MVC4 Complex Type Model is null after post发布后 MVC4 复杂类型模型为空
【发布时间】:2012-04-18 21:21:47
【问题描述】:

这是我的模特

public class AdministrationModel
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string EmailAddress { get; set; }
  public bool IsApproved { get; set; }
}

这是我的控制器

public ActionResult GetTabContent(string id)
{
  switch (id)
  {
   case "tab3":
   model = GetAllUsersInfo();
   viewName = "Administration";
   break;
   }
   return View(viewName);
 }

  private List<AdministrationModel> GetAllUsersInfo()
  {
    List<AdministrationModel> userList = new List<AdministrationModel>();
    foreach (MembershipUser user in Membership.GetAllUsers())
    {
      UserProfile userProfile = UserProfile.GetUserProfile(user.UserName);
      userList.Add(new AdministrationModel { EmailAddress = user.Email,                       IsApproved = user.IsApproved, FirstName = userProfile.FirstName, LastName = userProfile.LastName });
    }

    return userList;
  }

这是我的观点

@model List<AdminContainerModel>
@using (Html.BeginForm("Administration", "Account"))
{
  <fieldset>
    <div>
      @foreach (AdministrationModel AM in Model)
      {
        <div>
         <div class="colFull">@Html.DisplayFor(modelItem => AM.FirstName)</div>
         <div class="colFull">@Html.DisplayFor(modelItem => AM.LastName)</div>
         <div class="colFull">@Html.DisplayFor(modelItem => AM.EmailAddress)</div>
         <div class="colPartial"><input type="checkbox" checked="@AM.IsApproved"/>            </div>
      <div class="clear"></div>
    </div>
  }
</div>
 <input type="submit" value="Update Account" />
 </fieldset>
}

当用户单击更新帐户按钮时,它会转到控制器

  [HttpPost]
  public ActionResult Administration(List<AdministrationModel> model)
  {
     return View();
  }

在此方法中,模型始终为空。然而,呈现一切的视图是完美的,并显示了我想要它显示的内容。我做错了什么?

【问题讨论】:

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


    【解决方案1】:

    在使用集合时,为了正确处理它们,以便它们在后期模型绑定而不需要任何额外的工作,您需要确保它们被正确索引,您可以通过使用 for 循环来做到这一点,例如:

    @for (int i = 0; i < Model.Count; i++)
    {
        @Html.HiddenFor(m => m[i].FirstName)
        @Html.HiddenFor(m => m[i].LastName)
        @Html.HiddenFor(m => m[i].EmailAddress)
        <div>
            <div class="colFull">@Html.DisplayFor(m => m[i].FirstName)</div>
            <div class="colFull">@Html.DisplayFor(m => m[i].LastName)</div>
            <div class="colFull">@Html.DisplayFor(m => m[i].EmailAddress)</div>
            <div class="colPartial">@Html.CheckBoxFor(m => m[i].IsApproved)</div>
            <div class="clear"></div>
        </div>
    }
    

    这应该模型绑定没有任何其他代码:)

    编辑:抱歉我忘记了,displayFors 默认没有为模型绑定设置正确的属性,为其他没有 editorFor 的字段添加了 hiddenFors

    Edit2:根据您在评论中的其他问题,如果它是面向公众的,并且您不希望他们使用开发工具更改任何隐藏的值,请尝试以下操作:

    好的,所以您不希望他们更改 hiddenFors,这很好,但是您将需要某种 ID,以便在发布数据时知道哪个客户端是哪个客户端,我建议您不要在上面使用这些代码:

    @Html.HiddenFor(m => m[i].FirstName)
    @Html.HiddenFor(m => m[i].LastName)
    @Html.HiddenFor(m => m[i].EmailAddress)
    

    将它们替换为:

    @Html.HiddenFor(m => m[i].ClientId)
    

    这样您就不会发回名字、姓氏或电子邮件地址,而只是对已勾选或未勾选的实际客户的引用。

    要在关于跟踪原始值的评论中回答您的其他问题,在您的控制器方法中,您可以直接从数据库中获取原始值,然后您可以通过以下方法检测哪些不同,类似:

    [HttpPost]
    public ActionResult Administration(List<AdministrationModel> model)
    {
        var originalMatches = GetAllUsersInfo();
    
        var differences = (from o in originalMatches
                          join c in model on o.ClientId equals c.ClientId
                          where c.IsApproved != o.IsApproved).ToList()
    
        return View();
    }
    

    【讨论】:

    • 它不适合我。在回发事件中 - 名字、姓氏和电子邮件地址的所有值都为空。我想要所有已更改的集合(复选框从选中变为未选中或未选中变为选中)
    • 抱歉检查我的编辑,我忘记了 displayFors 没有将 Name 属性放在字段上以正确建模绑定(我们更改了模板来做到这一点)。在控制器中,您可以过滤掉未签入的链接,例如 var clients = model.Where(c => c.IsApproved).ToList()
    • 效果很好,但是我对此有两个问题:1. 如果有人更改隐藏字段值(几乎每个浏览器中的开发工具),那么模型中的值也会更改 2. lamda 表达式只给出所有已检查的列表,我如何跟踪已经检查和在此会话中检查的那些
    • 酷。 1. 它是一个您不想让人们操纵的面向公众的网站吗? 2. 您可以使您的模型成为包含两个客户列表的复杂类型,一个是您正在编辑的,一个是原始的。对两个集合重复上述 for 循环,但只保留原始集合的所有隐藏字段。
    • 只是想说声谢谢!用 for 替换 foreach 修复了绑定。
    【解决方案2】:

    您的@model 指令不正确,它应该是完全限定的类型名称。

    在这种情况下:

     @model TheNamespace.AdministrationModel
    

    在您更新问题之后。

    尝试使用:

    @Html.EditorFor(Model)
    

    这将为您的列表调用一个专门的编辑器模板。

    http://blogs.msdn.com/b/nunos/archive/2010/02/08/quick-tips-about-asp-net-mvc-editor-templates.aspx

    【讨论】:

    • 你说的是视图吗?如果是这样,我刚刚删除了命名空间以将其发布在此处。显示视图显示数据没有问题,在HTTPPost调用期间模型为空
    • 您想让我用 EditorFor 替换 DisplayFor 吗?我试过了,我的模型在发布后仍然为空。我确定我遗漏了一些东西(只是不确定它是什么)
    • 您需要一个映射AdministrationModel 的EditorTemplate 视图。 Html.EditorFor(Model) 将寻找此视图。使用后无需循环列表。
    • 好的,我有点让它以这种方式工作。但是,这会将模型中的所有内容呈现为可编辑字段。我想要编辑的只是“IsApproved”复选框。一旦选中/取消选中,我需要根据电子邮件地址查找用户并更新他/她。我希望这是有道理的。
    • 您可以在视图模型的属性上设置一些属性,这些属性表示自己是“不可编辑的” - 这应该会有所帮助:stackoverflow.com/questions/2876371/…
    【解决方案3】:

    如果您想在提交时返回带有模型的列表项,您将需要使用 for 循环,而不是 foreach

    【讨论】:

    • 这应该是一条评论
    • 如果他改变的只是 foreach 就可以了,所以这是一个解决方案
    • 好吧,你只是在“指出一些事情”——答案应该比这更深刻
    • 对不起,我想我想在写我的解决方案之前通过识别接受的答案来保持礼貌。即使内容相同,我还是将其改写为符合您的标准。
    • 我认为你误会了我 - 看看这个问题的公认答案。有很多内容可以解释答案并提供解决方案。这并不总是必要的,但如果您想说的话可以放入评论框中并且没有需要格式化的代码/内容 - 那么评论框就是它的地方
    【解决方案4】:

    马蒂的回答会奏效。

    如果您想避免必须指定索引(如果您有 ICollection,这将不起作用),您可以按照 Xander 的解释定义一个子模板。

    好处是您仍然可以在 AdminContainerModel 视图中获得所有强类型的智能感知,并且 MVC 在回发时为您开箱即用地将项目挂钩回您的列表。

    这是一个例子:

    主编辑器模板(正如 Xander 所说):

        @model IEnumerable<AdminContainerModel>
        @using (Html.BeginForm("Administration", "Account"))
        {
          <fieldset>
            <div>
              @Html.EditorForModel()
            </div?
          </fieldset>
        }
    

    AdminContainerModel 编辑器模板(这是为列表中的每个项目调用的,因为您调用了@Html.EditorForModel:

    @model AdminContainerModel
    <div>
        <div class="colFull">@Html.DisplayFor(modelItem => AM.FirstName)</div>
        <div class="colFull">@Html.DisplayFor(modelItem => AM.LastName)</div>
        <div class="colFull">@Html.DisplayFor(modelItem => AM.EmailAddress)</div>
        <div class="colPartial"><input type="checkbox" checked="@AM.IsApproved"/>            
    </div>
    <div class="clear"></div>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-11
      • 2018-01-04
      相关资源
      最近更新 更多