2012-03-04 6 views
5

새 개체를 만드는 경우 뷰 모델을 사용하는 가장 좋은 방법을 찾으려고합니다.ASP.NET MVC 3 뷰 모델 패턴

연락처 개체와 일부 회사 목록이 포함 된 매우 간단한보기 모델이 있습니다.

private ICompanyService _Service; 
public SelectList ContactCompanyList { get; private set; } 
public Contact contact { get; private set; } 

public ContactCompanyViewModel(Contact _Contact) 
{ 
    _Service = new CompanyService(); 
    contact = _Contact; 
    ContactCompanyList = GetCompanyList(); 
} 

private SelectList GetCompanyList() 
{ 
    IEnumerable<Company> _CompanyList = _Service.GetAll(); 
    return new SelectList(_CompanyList, "id", "name");  
} 

그런 다음이 뷰 모델을 사용하는 연락처 컨트롤러가있어서 내 연락처에 관련된 회사를 선택할 수 있습니다.

[Authorize] 
public ActionResult Create() 
{      
    return View(new ContactCompanyViewModel(new Contact())); 
} 

제 문제는 컨트롤러의 create 메소드 때문입니다.

[Authorize] 
[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Create(Contact _Contact) 
{ 
    try 
    { 
     _Service.Save(_Contact); 
     return RedirectToAction("Index"); 
    } 
    catch 
    { 
     return View(); 
    } 
} 

문제는보기가 빈 연락처 객체를 반환한다는 것입니다. 드롭 다운 목록에 명시 적으로 필드 이름이 선언되어 있기 때문에 회사 ID가 채워집니다. HTML.EditorFor 도우미를 사용하는 경우

@Html.DropDownList("parent_company_id",Model.ContactCompanyList) 

표준 HTML 양식 필드는 내가 만드는 행동으로 FormCollection를 사용하는 경우

@Html.EditorFor(model => model.contact.forename) 

내가 그들에 액세스 할 수 있습니다 ... contact.forename의 형식에서 객체 값을 전달 메서드 paremeter 및 명시 적으로 contact.value 검색하지만 연락처 개체를 매끄럽게 내 코드를 유지하고 매번 새 연락처 개체를 빌드 할 필요가 없습니다 매개 변수로 사용할 수 없습니다.

실제 뷰 모델 객체를 매개 변수로 전달하려고 시도했지만 생성자 오류가 발생합니다 (보기가 연락처 객체가 아닌보기 모델에 바인딩 될 때보기가 혼란 스럽습니다).

Html.EditFor 필드의 이름을 정의하여 내 컨트롤러에서 동작 만들기 메서드로 다시 전달할 때 값이 올바르게 연락처 개체에 매핑되도록하는 방법이 있습니까? 또는 어딘가에서 FUBAR 실수를 한 적이 있습니까? (이것이 학습 연습이므로 가장 가능성있는 설명입니다!)

답변

15

보기 모델이 잘못되었습니다. 뷰 모델은 어떤 서비스도 참조하면 안됩니다. 보기 모델은 도메인 모델을 참조하면 안됩니다. 뷰 모델에는 POST 액션 매개 변수로 사용할 수 있도록 매개 변수없는 생성자가 있어야합니다. 그래서 여기

은 시나리오에 대한보다 현실적인 뷰 모델의 :

public class ContactCompanyViewModel 
{ 
    public string SelectedCompanyId { get; set; } 
    public IEnumerable<SelectListItem> CompanyList { get; set; } 

    ... other properties that the view requires 
} 

다음 준비하고이 뷰 모델 채울 것 GET 동작 할 수 :

public ActionResult Create() 
{ 
    var model = new ContactCompanyViewModel(); 
    model.CompanyList = _Service.GetAll().ToList().Select(x => new SelectListItem 
    { 
     Value = x.id.ToString(), 
     Text = x.name 
    }); 
    return View(model); 
} 

과 POST 작업을 :

[HttpPost] 
public ActionResult Create(ContactCompanyViewModel model) 
{ 
    try 
    { 
     // TODO: to avoid this manual mapping you could use a mapper tool 
     // such as AutoMapper 
     var contact = new Contact 
     { 
      ... map the contact domain model properties from the view model 
     }; 
     _Service.Save(contact); 
     return RedirectToAction("Index"); 
    } 
    catch 
    { 
     model.CompanyList = _Service.GetAll().ToList().Select(x => new SelectListItem 
     { 
      Value = x.id.ToString(), 
      Text = x.name 
     }); 
     return View(model); 
    } 
} 

이제보기 모델에서 작업하십시오 :

@model ContactCompanyViewModel 
@using (Html.BeginForm()) 
{ 
    @Html.DropDownListFor(x => x.SelectedCompanyId, Model.CompanyList) 

    ... other input fields for other properties 

    <button type="submit">Create</button> 
} 
+0

고마워요. 제가보기 모드를 만들기 작업 방법에 매핑 할 수있게하여 문제를 해결했습니다. 드롭 다운 값이 바인딩되지 않은 유일한 문제는 드롭 다운 이름을 변경하여 해결했습니다. ~ ** @ Html.DropDownList ("contact.parent_company_id", Model.ContactCompanyList).** 내 유일한 질문은 수동으로 매핑하는 이유입니다. 채워진 연락처 객체를 포함하는 모델이 있습니다. 매핑 할 것이 없습니다. –

+1

@DavidAbraham, 프로세스를 설명하기 위해 수동으로 매핑했습니다. 실제 응용 프로그램에서는 AutoMapper를 사용합니다. http://automapper.org/이 작업을 수행합니다. –

+0

그러나 다시 Automapper가 필요하지 않습니다. 제 경우에는 이제 완전히 채워지는 연락처 도메인 객체를 포함하는 viewmodel 객체를 다시 전달했습니다. 매핑 할 것이 없습니다. 자동 매퍼는 어디에 있습니까? –