总是在MVC中使用ViewModel模式?

时间:2014-05-18 14:55:52

标签: c# asp.net-mvc asp.net-mvc-5 asp.net-mvc-viewmodel

在控制器的MVC中,您应该从DB获取Model并将其转换为ViewModel,然后再将其发送到View。通常使用像Automapper这样的东西。

我的问题是,如果你需要在视图中显示模型的所有属性,是否值得创建一个ViewModel?

如果Model和ViewModel需要相同,那么创建ViewModel会在应用中创建一些安全性或好处,或者我们只会增加不必要的复杂性?

5 个答案:

答案 0 :(得分:8)

使用视图模型的关键通常是因为您的视图需要比域模型提供的信息更多/更少的信息。

其他好处包括将您的视图与您的域分离,如果您的域名发展,这可能会导致您的视线变得脆弱。

关键在于,它们不是必需品;视图模型的目的是为视图提供所需的信息以呈现自身,如果您认为应用中的视图模型是多余的,则不要使用它。但是,我至少会考虑使用接口来避免耦合。

答案 1 :(得分:6)

除了已经提到的(关注点分离,解耦等)之外,单独的ViewModel会阻止可能与DB模型一起出现的抽象泄漏。如果您在启用导航属性的情况下使用EF,则尤其如此。

假设你有汽车和轮子。您正在视图中显示汽车。

案例1(对于汽车没有单独的ViewModel):在剃刀视图中,很容易得到类似下面的内容:

  public class CarModelFromDB
  {
      public string CarName{get;set;}
      //More properties
      public IEnumerable<Wheel> Wheel{get;set;}
  }  

  @model IEnumerable<CarModelFromDB>

  @foreach(var car in Model)
  {
      //some View Code
      @foreach(var wheel in car.Wheels.Where(x=>x.IsRound=true))
      {
         <span>wheel.Color</span> 
         // some View Code
      }
  }

现在,您获取汽车轮子的逻辑已泄漏到视图中,并且已启用select N+1 situation。我认为没有任何简单的方法可以测试它。

案例2(使用ViewModel对于汽车):在这种情况下,您可以通过仅发送所需内容来限制视图。它可能如下所示:

  public class CarViewModel
  {
      public string CarName{get;set;}
      //More properties
      public IEnumerable<string> WheelColors{get;set;}
  }  

  @model IEnumerable<CarViewModel>
  @foreach(var car in Model)
  {
      //some View Code
      @foreach(var wheelColor in WheelColor)
      {
         <span>wheelColor</span> 
         // some View Code
      }
  }

现在,您的视图代码在其功能方面受到很大限制,并且不会向数据库发送任何恶意查询。您的控制器可以真正控制视图的获取。你可以在那里推动轮逻辑,或者理想地在一些从动作方法调用的服务方法中。此外,您可以对操作方法进行适当的测试,并对您的系统充满信心。我希望这会有所帮助。

<强>更新

案例3(动态ViewModel):  如果您对dynamic types感到满意,则可以避免所有的转换和映射。只要您的视图获得所需的属性,它就会很高兴。这些来自哪里并不重要。所以代码将是:

  public class CarViewModel
  {
      public string CarName{get;set;}
      //More properties
      public IEnumerable<string> WheelColors{get;set;}
  }  

  // pass the List<CarViewModel> to the view

  @model dynamic
  @foreach(var car in Model)
  {
      //some View Code
      @foreach(var wheelColor in WheelColor)
      {
         <span>wheelColor</span> 
         // some View Code
      }
  }

潜在的缺点/额外工作是确保您对模型上存在这些属性进行测试。

再次像之前提到的那样,这不应该被认为是适合所有类型解决方案的一种尺寸。这些是一些选项,只有在它们有意义时才使用。

答案 2 :(得分:4)

虽然这个问题最有可能以主要基于意见的方式结束,但这确实是一个很好的问题。 ViewModel几乎总是值得在边缘复杂的应用程序中付出努力。

大多数应用都可以从Viewmodel扩展所有BaseViewModel.cs,从而可以显示CurrentTab(突出显示当前导航栏页面)或PageTitle等内容在_Layout.cshtml。在这种情况下,视图模型始终是BaseViewModel的衍生物所必需的。

答案 3 :(得分:3)

这是不可能的,因为我们不知道您的模型是什么以及是否存在任何安全问题。

通常,安全问题不在于将模型传递给视图,而在于接收自动绑定到数据模型的帖子。如果你有敏感信息,那么有人可以制作一个会改变你不想要的东西的帖子。

请参阅http://odetocode.com/blogs/scott/archive/2012/03/12/complete-guide-to-mass-assignment-in-asp-net-mvc.aspx

更大的问题是,他们真的一样吗?你确定他们会保持不变吗?您确定不需要进行更改,这些更改要求视图模型对数据模型的某些要求有不同的要求吗?

预先完成工作并遵循良好的设计比在以后需要时尝试修复更容易。

答案 4 :(得分:3)

您的假设是额外的层增加了复杂性,冗余,映射和同步的额外开发时间,这是正确的。但是这个缺点很容易在大型复杂的应用程序中被吸收,特别是在团队环境中,不同的团队被分配到不同的层。

对于少数开发人员的小项目(在您的情况下通常为1),可以在UI中使用相同的模型。它很小,你可以在它生长时轻松拍打额外的图层。

ViewModel的目的是支持关注点分离,这是MVC的主要卖点。这种分离允许您的演示文稿和域安全地独立发展。您可以保护域免受演示文稿中的任何更改,并且可以保护演示文稿免受域中的任何更改。

您可能不会在早期注意到这一点,但从长远来看,域和演示文稿可以保证更改,并且您的代码需要在发生这种情况时做好准备。这是你今天的计划,明天会让你保持理智。

此外,有许多方法可以自动化从域模型到视图模型的映射,例如AutoMapper等工具。