ASP.NET MVC 3 Viewmodel模式

Dav*_*ham 5 asp.net-mvc-3

我正在尝试在创建新对象的情况下找出使用viewmodel的最佳方法.

我有一个非常简单的视图模型,其中包含联系对象和公司的选择列表.

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");       
}
Run Code Online (Sandbox Code Playgroud)

然后我有联系控制器使用这个视图模型,并让我为我的联系人选择一个相关的公司.

[Authorize]
public ActionResult Create()
{                       
    return View(new ContactCompanyViewModel(new Contact()));
}
Run Code Online (Sandbox Code Playgroud)

我的问题是控制器上的create方法.

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

问题是视图返回一个空的联系人对象,但是!填充公司ID,这是因为下拉列表显式声明了其字段名称.

 @Html.DropDownList("parent_company_id",Model.ContactCompanyList)
Run Code Online (Sandbox Code Playgroud)

标准的html表单字段以contact.forename使用HTML.EditorFor帮助程序时的格式传回对象值...

@Html.EditorFor(model => model.contact.forename)
Run Code Online (Sandbox Code Playgroud)

我可以访问它们,如果我使用一个FormCollection作为我的创建操作方法paremeter然后显式搜索contact.value但我不能使用Contact对象作为参数来保持我的代码漂亮和干净,而不必每次都建立一个新的联系人对象.

我尝试将实际的视图模型对象作为参数传回,但这只会导致构造函数错误(由于视图绑定到视图模型而不是联系对象,因此看起来很混乱).

有没有一种方法可以定义Html.EditFor字段的名称,以便在传回控制器上的create action方法时,值正确映射回联系对象?或者我在某处犯了一些FUBAR错误(这是最可能的解释,因为这是一次学习练习!).

Dar*_*rov 15

您的视图模型似乎有误.View模型不应该引用任何服务.视图模型不应引用任何域模型.视图模型应该具有无参数构造函数,以便它们可以用作POST操作参数.

所以这是一个更逼真的场景视图模型:

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

    ... other properties that the view requires
}
Run Code Online (Sandbox Code Playgroud)

然后你可以有一个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);
}
Run Code Online (Sandbox Code Playgroud)

和一个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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在在您的视图中,您可以使用视图模型:

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

    ... other input fields for other properties

    <button type="submit">Create</button>
}
Run Code Online (Sandbox Code Playgroud)

  • @DavidAbraham,我的答案的全部意义在于视图模型不应包含域模型. (3认同)