在ASP.NET MVC 3中使用视图模型

我对查看模型比较新,我遇到了一些使用它们的问题。 这是一种情况,我想知道最佳做法是什么……

我将视图所需的所有信息都放入视图模型中。 这是一个例子 – 请原谅任何错误,这是我的头顶编码。

public ActionResult Edit(int id) { var project = ProjectService.GetProject(id); if (project == null) // Something about not found, possibly a redirect to 404. var model = new ProjectEdit(); model.MapFrom(project); // Extension method using AutoMapper. return View(model); } 

如果屏幕只允许编辑一个或两个字段,当视图模型返回时,它会丢失相当多的数据(应该是这样)。

 [HttpPost] public ActionResult Edit(int id, ProjectEdit model) { var project = ProjectService.GetProject(id); if (project == null) // Something about not found, possibly a redirect to 404. try { if (!ModelState.IsValid) return View(model) // Won't work, view model is incomplete. model.MapTo(project); // Extension method using AutoMapper. ProjectService.UpdateProject(project); // Add a message for the user to temp data. return RedirectToAction("details", new { project.Id }); } catch (Exception exception) { // Add a message for the user to temp data. return View(model) // Won't work, view model is incomplete. } } 

我的临时解决方案是从头开始重新创建视图模型,从域模型重新填充它,将表单数据重新应用到它,然后照常进行。 但这使得视图模型参数有些无意义。

 [HttpPost] public ActionResult Edit(int id, ProjectEdit model) { var project = ProjectService.GetProject(id); if (project == null) // Something about not found, possibly a redirect to 404. // Recreate the view model from scratch. model = new ProjectEdit(); model.MapFrom(project); // Extension method using AutoMapper. try { TryUpdateModel(model); // Reapply the form data. if (!ModelState.IsValid) return View(model) // View model is complete this time. model.MapTo(project); // Extension method using AutoMapper. ProjectService.UpdateProject(project); // Add a message for the user to temp data. return RedirectToAction("details", new { project.Id }); } catch (Exception exception) { // Add a message for the user to temp data. return View(model) // View model is complete this time. } } 

有更优雅的方式吗?

编辑

这两个答案都是正确的,所以如果可以,我会奖励他们。 然后点头转向MJ,因为经过反复试验后我发现他的解决方案是最精简的。

吉米,我仍然可以使用助手。 如果我将我需要显示的内容添加到视图包(或查看数据),就像这样……

 ViewBag.Project= project; 

然后我可以做以下事情……

 @Html.LabelFor(model => ((Project)ViewData["Project"]).Name) @Html.DisplayFor(model => ((Project)ViewData["Project"]).Name) 

有点破解,它需要在某些情况下使用System.ComponentModel.DisplayNameAttribute修饰域模型,但我已经这样做了。

我很乐意打电话给…

 @Html.LabelFor(model => ViewBag.Project.Name) 

但动态会导致表达式出现问题。

经过一些试错(也就是代码,然后讨厌它)的学习,我目前首选的方法是:

我只使用视图模型来绑定输入字段。 因此,在您的情况下,如果您的视图仅编辑两个字段,那么您的视图模型将只有两个属性。 对于填充视图所需的数据(下拉列表,标签等),我使用动态ViewBag。

我相信显示视图(即填充视图需要显示的任何内容),以及捕获已发布的表单值(绑定,validation等)是两个独立的问题。 我发现将填充视图所需的数据与从视图中回发的数据混合起来会变得混乱,并且更经常地创建您的情况。 我不喜欢部分填充的物体被传递。

我不确定如何使用Automapper(用于将域对象映射到动态ViewBag),因为我还没有使用它。 我相信它有一个可能有效的DynamicMap方法吗? 将发布的强类型ViewModel自动映射到Domain对象上不应该有任何问题。

如果我理解正确,您的viewmodel可能看起来与您的域实体非常相似。 您提到viewmodel可以返回大部分为空,因为只有某些字段是可编辑的。

假设您有一个视图,其中只有少数字段可用于编辑(或显示),这些是您应在viewmodel中提供的唯一字段。 我通常为每个视图创建一个viewmodel,让控制器或服务处理用户的输入,并在执行一些validation后将其映射回域实体。

这是一个关于视图模型的最佳实践的线程,您可能会发现它很有用。

编辑:您还可以在编辑/ POST操作中接受与编辑/ GET操作相关的不同视图模型。 我相信只要模型绑定器可以解决这个问题,这应该可行。