为什么我们使用ViewModels?

mri*_*ula 24 asp.net-mvc

我最近开始作为Web开发人员工作.我使用ASP .NET MVC 4和NHibernate.

在我的工作场所,我们严格使用视图模型在控制器和视图之间来回传输数据.并且视图模型不应包含模型的任何对象.我知道它是控制器和视图之间的一种层.

但是我发现编写一个viewmodel类是重复和冗余的,即使我们可以直接将模型的对象发送到视图(在大多数情况下).

例如,如果我想显示订单,我可以在控制器的操作中执行此操作 -

return View(Repository.Get<Order>(id));
Run Code Online (Sandbox Code Playgroud)

但相反,我必须编写一个viewmodel,用获取的顺序填充它,然后将其传递给视图.

所以,我的问题是,当我们可以使用模型的对象时,编写视图模型的目的是什么?

Dai*_*Dai 16

对于较小的项目,你是对的.我听到了你的观点并表示同情 - 但是有充分理由这样做,这是一种乏味和重复的工作,特别是在更大更复杂的应用中:

  • 在Controller的操作中执行所有处理至关重要.但是在您给出的示例中,该Repository.Get方法可能会返回一个延迟评估的IQueryable对象,这意味着在评估View之前不会命中DB.出于各种原因,这很糟糕.(解决方法是.ToList在仍在控制器中时调用).
  • "视图不应包含任何非表示逻辑"和"您不应该信任视图"(因为视图可以由用户提供).通过提供Model对象(可能仍然连接到活动的DatabaseContext),视图可以对数据库进行恶意更改.
  • View的数据显示并不总是与其Model的数据进行1:1的映射,例如考虑用户详细信息页面:

    用户的EF模型对象在数据库中表示其实体,因此它可能如下所示:User { UserId, UserName, PasswordHash, PasswordSalt, EmailAddress, CreatedDate },而"用户详细信息"页面上的字段将是User { UserId, UserName, Password, ConfirmYourPassword, EmailAddress },您是否看到了区别?因此,您不能使用EF User模型作为视图模型,您必须使用单独的类.

  • 模型操作的危险:如果你让ASP.NET MVC(或任何其他框架)将模型绑定到传入的HTTP POST请求(然后采用上面的用户详细信息示例),用户可以通过伪造UserId属性值来重置任何人的密码.ASP.NET将在绑定期间重写该值,除非您专门对其进行清理(这与制作单个ViewModel一样麻烦),否则此漏洞将保留.

  • 在有多个开发人员在团队工作的项目中,一切都是一致的很重要.让一些页面使用定制的ViewModel而不是其他使用EF模型的页面是不一致的,因为团队没有共同的思想,事情必须记录下来并且通常是有意义的.出于同样的原因,单个开发人员可以在他的源代码中没有过多的XML文档的情况下逃脱,但是在团队情况下,如果不这样做,你就会崩溃.

在您的情况下我会与您分享一些轻微的解决方法,但请注意前提条件:

  • 您的观点可以完全信任
  • 您的视图仅包含表示逻辑
  • 您的应用程序主要是CRUD
  • 您的视图与每个EF实体模型1:1对应(即没有JOIN)
  • 您的视图仅处理POST表单的单个简单模型,而不是复杂模型(即对象图)

...然后你可以这样做:

  • 将所有单向,非形式相关的数据放入您的ViewData集合或ViewBagMVC 4(ViewData<T>如果您是硬核,甚至是通用的).这对于存储HTML页面标题和与母版页共享数据非常有用.
  • 使用经过全面评估和加载的 EF模型作为View<TModel>模型.

但请谨慎使用此方法,因为它可能会引入不一致.