ASP.NET MVC 3 Viewmodel模式

时间:2012-03-04 10:00:04

标签: 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");       
}

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

[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.DropDownList("parent_company_id",Model.ContactCompanyList)

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

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

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

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

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

1 个答案:

答案 0 :(得分:15)

您的视图模型似乎有误。 View模型不应该引用任何服务。视图模型不应引用任何域模型。视图模型应具有无参数构造函数,以便它们可用作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>
}