C# 是否始终在MVC中使用ViewModel模式?

C# 是否始终在MVC中使用ViewModel模式?,c#,asp.net-mvc,asp.net-mvc-5,asp.net-mvc-viewmodel,C#,Asp.net Mvc,Asp.net Mvc 5,Asp.net Mvc Viewmodel,在控制器的MVC中,您应该从DB获取模型,并在将其发送到视图之前将其转换为ViewModel。通常使用Automapper之类的工具 我的问题是,如果需要在视图中按原样显示模型的所有属性,那么创建ViewModel是否值得 如果模型和ViewModel需要相同,那么创建ViewModel会在应用程序中带来一些安全性或好处,或者我们只是增加了不必要的复杂性?这是不可能的,因为我们不知道您的模型是什么以及是否存在任何安全问题 一般来说,安全问题不在于将模型传递给视图,而在于接收自动绑定到数据模型的帖

在控制器的MVC中,您应该从DB获取模型,并在将其发送到视图之前将其转换为ViewModel。通常使用Automapper之类的工具

我的问题是,如果需要在视图中按原样显示模型的所有属性,那么创建ViewModel是否值得


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

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

一般来说,安全问题不在于将模型传递给视图,而在于接收自动绑定到数据模型的帖子。如果你有敏感的信息在那里,有可能有人制作一个帖子来改变你不想做的事情

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


提前做好工作,遵循好的设计,要比在需要时尝试在以后进行修复容易得多。

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


大多数应用程序将受益于从
BaseViewModel.cs
扩展所有
Viewmodel
,这样
CurrentTab
(突出显示当前导航栏页面)或
PageTitle
之类的内容就可以显示在
\u Layout.cshtml
中。在这种情况下,viewmodel始终是作为
BaseViewModel

的衍生产品所必需的。使用视图模型的目的通常是因为您的视图需要比域模型提供的更多/更少的信息

其他好处包括将您的视图与您的域分离,如果您的域发生变化,这可能会导致脆弱性


关键是,它们不是必要的;视图模型的目的是仅为视图提供渲染自身所需的信息,如果您觉得应用程序中的视图模型是多余的,则不要使用它。不过,我至少应该考虑使用接口来避免耦合。

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

对于只有几个开发人员的小项目(在您的例子中通常是1个),在UI中使用相同的模型是可以的。因为它很小,所以当它生长时,你可以很容易地拍打它

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

您可能在早期没有注意到这一点,但从长远来看,域和表示肯定会发生更改,并且您的代码需要在发生这种情况时准备就绪。你今天的计划将使你明天保持清醒


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

除了前面提到的方法(分离关注点、解耦等),单独的视图模型可以阻止DB模型可能带来的抽象泄漏。这是正确的,尤其是当您使用启用了导航属性的EF时

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

案例1(汽车没有单独的视图模型):在razor视图中,很容易得到如下内容:

  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
      }
  }
  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
      }
  }
公共类CarModelFromDB
{
公共字符串CarName{get;set;}
//更多属性
公共IEnumerable Wheel{get;set;}
}  
@模型IEnumerable
@foreach(模型中的var车辆)
{
//一些视图代码
@foreach(汽车中的var车轮。车轮。其中(x=>x.IsRound=true))
{
轮子。颜色
//一些视图代码
}
}
现在,您获取汽车车轮的逻辑已泄漏到视图中,并且已启用。我也不认为有任何简单的测试方法

案例2(使用适用于汽车的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
      }
  }
  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
      }
  }
公共类CarViewModel
{
公共字符串CarName{get;set;}
//更多属性
公共IEnumerable WheelColor{get;set;}
}  
@模型IEnumerable
@foreach(模型中的var车辆)
{
//一些视图代码
@foreach(wheelColor中的var wheelColor)
{
车轮颜色
//一些视图代码
}
}
现在,视图代码的功能非常有限,它不会向数据库发送任何恶意查询。您的控制器可以真正控制视图的内容。您可以将控制盘逻辑推到其中,或者理想情况下推到从action方法调用的某个服务方法中。此外,您可以对action方法进行适当的测试,并对您的系统充满信心。我希望这有帮助

更新

案例3(动态视图模型): 如果您熟悉,可以避免所有的强制转换和映射。只要您的视图获得所需的属性,它就会很高兴。这些来自哪里并不重要。因此,代码将是:

  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
      }
  }
公共类CarViewModel
{
公共字符串CarName{get;set;}
//更多属性
公共IEnumerable WheelColor{get;set;}
}  
//将列表传递给视图
@模型动力学
@foreach(var car i