发布后,MVC4复杂类型模型为空

时间:2012-04-18 21:21:47

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

这是我的模特

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

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

4 个答案:

答案 0 :(得分:10)

当使用集合时,为了正确处理它们以便它们在帖子上进行模型绑定而不需要任何额外的工作,你需要确保它们被正确编入索引,你可以通过使用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默认情况下不为模型绑定添加正确的属性,为没有编辑器的其他字段添加hiddenFors

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

好的,所以你不希望他们改变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();
}

答案 1 :(得分:1)

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

答案 2 :(得分:0)

如果要在提交时返回模型列表项,则需要使用for循环,而不是foreach

答案 3 :(得分:0)

马蒂的回答将起作用。

如果您想避免必须指定索引(如果您有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>