我刚刚学习ASP.NET MVC 3而且我对如何实现类似于此链接中显示的内容感到困惑:
http://www.codethinked.com/easy-and-safe-model-binding-in-aspnet-mvc
为什么我很困惑很可能是基于我对这个主题的无知。在上面链接的页面上的示例中,我看到Justin使用的ViewModel直接包含其“Person”对象的属性。
我想要做的是类似的,但我希望ViewModel实际上包含域类,在我的案例中是公司,而不是Person。我正在使用Company类本身实现ViewModel子集视图(例如IEditCompanyAsUser)。
到目前为止,我所尝试的内容看起来像是这样:
public class Company : IValidatableObject, ICompanyUpdateAsUser
{
[Key]
[ScaffoldColumn(false)]
public virtual int CompanyID { get; set; }
[Required]
public virtual Boolean Active { get; set; }
[Required]
public virtual string Name { get; set; }
[Required]
public virtual string Phone { get; set; }
// Containing some more members below
}
使用包含属性的ICompanyUpdateAsUser我希望我的控制器的Edit方法更新:
public interface ICompanyUpdateAsUser
{
bool Active { get; set; }
string Name { get; set; }
string Phone { get; set; }
}
ViewModel类看起来像这样:
public class CompanyViewModel
{
public Company Company;
// Will be adding more members in the future
}
我无法弄清楚如何正确编码控制器。我的控制器目前看起来像这样:
/// <summary>
/// POST: /Company/Edit/5
/// </summary>
[HttpPost]
public ActionResult Edit([Bind(Prefix="Company")]Company model)
{
var company = _companyService.GetCompany(model.CompanyID);
if (company == null)
return RedirectToAction("Index");
if (ModelState.IsValid)
{
if (TryUpdateModel<ICompanyUpdateAsUser>(company))
{
_companyService.SaveCompany();
return RedirectToAction("Details", new { companyId = model.CompanyID });
}
}
return View(model);
}
我知道我的控制器代码完全有问题,但我无法弄清楚我需要使用哪些组件来实现这样的模式?我需要使用自定义模型绑定器吗?我是否需要使用ASP.NET MVC3的其他一些功能来实现该模式?
任何建议都将不胜感激。
谢谢!
*的 修改 *
我需要做的是让Edit视图回发一个“Company”对象,然后使用post'ed Company上的值(根据传递给TryUpdateModel的接口上的属性)从数据库更新对象。一切似乎都在起作用(验证等),但TryUpdateModel(公司)似乎没有工作,尽管评估为true。当我使用调试器逐步执行代码时,从数据库中提取的公司对象永远不会更新。
经过多一点阅读后,我确定TryUpdateModel方法更新了方法的IValueProvider中传递的项目。如何将传入的“公司模型”与方法的IValueProvider相关联?
答案 0 :(得分:2)
我最后通过首先进行一些修改来解决问题。在我的问题中,我的控制器无法使用我创建的ViewModel类。一旦我将控制器修改为如此:
/// <summary>
/// POST: /Company/Edit/5
/// </summary>
[HttpPost]
public ActionResult Edit(CompanyViewModel viewModel)
{
var company = _companyService.GetCompany(viewModel.Company.CompanyID);
if (company == null)
return RedirectToAction("Index");
if (ModelState.IsValid)
{
if (TryUpdateModel<ICompanyUpdateAsUser>(company, "Company"))
{
_companyService.SaveCompany();
return RedirectToAction("Details", new { companyId = viewModel.Company.CompanyID });
}
}
return View(viewModel);
}
我发现一切似乎都正常工作,但正如上面的评论中所述,TryUpdateModel根本无法正常工作,尽管返回true!
筛选了大量Stack Overflow&amp;其他论坛帖子,我最终发现TryUpdateModel不适用于字段,只适用于属性。为了使其正常工作,我必须修改我的ViewModel,如下所示:
public class CompanyViewModel
{
public Company Company { get; set; }
public CompanyViewModel(Company company)
{
Company = company;
}
public CompanyViewModel()
{
Company = new Company();
}
}
这是一个愚蠢的错误,虽然我觉得我读过的很多模型绑定教程都忽略了这一点。
希望这个答案可以节省一些时间。
答案 1 :(得分:0)
TryUpdateModel应该有一个带有前缀的重载。由于听起来您的原始视图模型包含您的Company对象,因此为Company对象生成的表单字段的名称(假设您使用的是标准表单输入名称)包含前缀“Company”,它看起来像您已经使用该方法所采用的模型识别出这一点,请在更新域对象时尝试使用相同的前缀。
仅供参考,在视图模型中使用域对象通常不是最佳做法,主要原因是可能存在您不希望用户更新的字段。如果用户对您的域有足够的了解,他们可以在帖子数据中添加其他表单字段,而MVC会盲目地更新这些属性/字段,这可能会导致问题。有一些方法可以告诉MVC在绑定时排除某些属性/字段,但它会成为维护的噩梦,通常更容易为视图使用单独的对象。