2011-12-24 2 views
2

편집기 템플릿을 사용하여 사용자가 할당 할 수있는 각 역할에 대한 확인란을 표시합니다. 이 모델은 다음과 같습니다편집기 템플릿의 확인란은 사후 작업에서 모델에 바인딩되지 않습니다.

public class UserModel 
{ 
    [Required] 
    [Display(Name = "User name")] 
    public string UserName { get; set; } 

    [Required] 
    [DataType(DataType.EmailAddress)] 
    [Display(Name = "Email address")] 
    public string Email { get; set; } 

    [Required] 
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 
    [DataType(DataType.Password)] 
    [Display(Name = "Password")] 
    public string Password { get; set; } 

    [DataType(DataType.Password)] 
    [Display(Name = "Confirm password")] 
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 
    public string ConfirmPassword { get; set; } 

    public IEnumerable<string> UserRoles { get; set; } 
} 
public class UserRoleModel 
{ 
    public IEnumerable<RoleViewModel> AllRoles { get; set; } 
    public UserModel user { get; set; } 

    public UserRoleModel() 
    { 
     this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel 
     { 
      Name = r 
     }); 
     this.user = new UserModel(); 
    } 
} 
public class RoleViewModel 
{ 
    public string Name { get; set; } 
    public bool Selected { get; set; } 
} 

감사관 :

public ActionResult Create() 
    { 
     return View(new UserRoleModel()); 
    } 

    [HttpPost] 
    public ActionResult Create(UserRoleModel model) 
    { 
     if (ModelState.IsValid) 
     { 
      MembershipCreateStatus createStatus; 
      Membership.CreateUser(model.user.UserName, model.user.Password, model.user.Email, null, null, true, null, out createStatus); 

      if (createStatus == MembershipCreateStatus.Success) 
      { 


       foreach (var r in model.AllRoles) 
       { 
        if (r.Selected) 
        { 
         Roles.AddUserToRole(model.user.UserName, r.Name); 
        } 
       } 

       return RedirectToAction("Index", "Home"); 
      } 
      else 
      { 
       ModelState.AddModelError("", ErrorCodeToString(createStatus)); 
      } 
     } 

     return View(model); 
    } 

뷰 :

@model BBmvc.Areas.Tools.Models.UserRoleModel 


@using (Html.BeginForm()) { 
@Html.ValidationSummary(true) 
<fieldset> 
    <legend>UserModel</legend> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.user.UserName) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.user.UserName) 
     @Html.ValidationMessageFor(model => model.user.UserName) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.user.Email) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.user.Email) 
     @Html.ValidationMessageFor(model => model.user.Email) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.user.Password) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.user.Password) 
     @Html.ValidationMessageFor(model => model.user.Password) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.user.ConfirmPassword) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.user.ConfirmPassword) 
     @Html.ValidationMessageFor(model => model.user.ConfirmPassword) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(x => x.AllRoles) 
    </div> 


    <p> 
     <input type="submit" value="Create" /> 
    </p> 
</fieldset> 

}

하고 편집기 템플릿

@model BBmvc.Areas.Tools.Models.RoleViewModel 
@Html.CheckBoxFor(x => x.Selected) 
@Html.LabelFor(x => x.Selected, Model.Name) 
@Html.HiddenFor(x => x.Name) 
<br /> 

문제는 확인란을 선택했는지 여부와 상관없이 게시 작업에서 아무런 차이가 없다는 것입니다. 어떻게 든 모델에 묶이지는 않는 것 같습니다.

답변

1

문제는 LINQ 쿼리의 지연된 실행에서 비롯됩니다.

public class UserRoleModel 
{ 
    public IEnumerable<RoleViewModel> AllRoles { get; set; } 
    public UserModel user { get; set; } 

    public UserRoleModel() 
    { 
     this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel 
     { 
      Name = r 
     }).ToList(); 
     this.user = new UserModel(); 
    } 
} 

을 주목 .ToList() 전화 :

this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel 
{ 
    Name = r 
}).ToList(); 

그리고 여기의 설명이다 당신은 열심히 컬렉션을 초기화 할 필요가있다. 당신이 쓸 때 :

this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel 
{ 
    Name = r 
}); 

이 순간에 쿼리는 실행되지 않습니다. 표현식 트리 만 작성되지만 실제 쿼리는 콜렉션에 대한 반복 작업이 시작될 때만 실행됩니다. 그리고 반복 시작은 무엇입니까? 먼저보기입니다. 뷰 내부 당신이 컬렉션에 대한 편집기 템플릿을 사용 AllRoles 이후

@Html.EditorFor(x => x.AllRoles) 

는 ASP.NET MVC가 자동으로 반복하고 컬렉션의 각 요소에 대해 편집기 템플릿을 렌더링 컬렉션 속성입니다. 이렇게하면 뷰가 제대로 렌더링됩니다.

이제 양식을 게시 할 때 어떤 일이 발생하는지 살펴 보겠습니다. Create 액션에 게시하고 기본 모델 바인더가 시작됩니다. 생성자가 호출되지만 이번에는 AllRoles 속성을 반복 할 것이 없으므로 이번에는 쿼리가 실행되지 않습니다. 사실 그것은 액션 내부에서 나중에 실행되고 값은 손실됩니다.

이 이유 때문에 생성자 내부에서보기 모델을 초기화하지 않는 것이 좋습니다. 각각의 컨트롤러 액션 내에서이 작업을 수행하는 것이 더 될 것이다 : 다음

public class UserRoleModel 
{ 
    public IEnumerable<RoleViewModel> AllRoles { get; set; } 
    public UserModel user { get; set; } 
} 

과 :

public ActionResult Create() 
{ 
    var model = new UserRoleModel 
    { 
     AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel 
     { 
      Name = r 
     }).ToList(), 
     user = new UserModel() 
    }; 
    return View(model); 
} 
+0

우수! 감사! – Rob

관련 문제