468

我是 ASP.NET MVC 的新手。我无法理解 ViewModel 的用途。

什么是 ViewModel,为什么我们需要一个用于 ASP.NET MVC 应用程序的 ViewModel?

如果我能得到一个关于它的工作和解释的好例子,那就更好了。

4

15 回答 15

661

Aview model表示您希望在视图/页面上显示的数据,无论是用于静态文本还是用于可以添加到数据库(或编辑)的输入值(如文本框和下拉列表)。它与您的domain model. 它是视图的模型。

假设您有一个Employee代表您的员工域模型的类,它包含以下属性(唯一标识符、名字、姓氏和创建日期):

public class Employee : IEntity
{
     public int Id { get; set; }

     public string FirstName { get; set; }

     public string LastName { get; set; }

     public DateTime DateCreated { get; set; }
}

视图模型与域模型的不同之处在于,视图模型仅包含您要在视图上使用的数据(由属性表示)。例如,假设您要添加新的员工记录,您的视图模型可能如下所示:

public class CreateEmployeeViewModel
{
     public string FirstName { get; set; }

     public string LastName { get; set; }
}

如您所见,它仅包含两个属性。这两个属性也在员工域模型中。为什么会这样? Id可能不是从视图中设置的,它可能是由 Employee 表自动生成的。并且DateCreated也可能设置在存储过程或应用程序的服务层中。因此IdDateCreated视图模型中不需要。当您将员工的详细信息(已被捕获的员工)作为静态文本查看时,您可能希望显示这两个属性。

加载视图/页面时,员工控制器中的 create 操作方法将创建此视图模型的实例,如果需要填充任何字段,然后将此视图模型传递给视图/页面:

public class EmployeeController : Controller
{
     private readonly IEmployeeService employeeService;

     public EmployeeController(IEmployeeService employeeService)
     {
          this.employeeService = employeeService;
     }

     public ActionResult Create()
     {
          CreateEmployeeViewModel model = new CreateEmployeeViewModel();

          return View(model);
     }

     public ActionResult Create(CreateEmployeeViewModel model)
     {
          // Do what ever needs to be done before adding the employee to the database
     }
}

您的视图/页面可能如下所示(假设您正在使用ASP.NET MVC视图Razor引擎):

@model MyProject.Web.ViewModels.CreateEmployeeViewModel

<table>
     <tr>
          <td><b>First Name:</b></td>
          <td>@Html.TextBoxFor(m => m.FirstName, new { maxlength = "50", size = "50" })
              @Html.ValidationMessageFor(m => m.FirstName)
          </td>
     </tr>
     <tr>
          <td><b>Last Name:</b></td>
          <td>@Html.TextBoxFor(m => m.LastName, new { maxlength = "50", size = "50" })
              @Html.ValidationMessageFor(m => m.LastName)
          </td>
     </tr>
</table>

因此,验证将仅在FirstName和上进行LastName。使用FluentValidation,您可能会进行如下验证:

public class CreateEmployeeViewModelValidator : AbstractValidator<CreateEmployeeViewModel>
{
     public CreateEmployeeViewModelValidator()
     {
          RuleFor(m => m.FirstName)
               .NotEmpty()
               .WithMessage("First name required")
               .Length(1, 50)
               .WithMessage("First name must not be greater than 50 characters");

          RuleFor(m => m.LastName)
               .NotEmpty()
               .WithMessage("Last name required")
               .Length(1, 50)
               .WithMessage("Last name must not be greater than 50 characters");
     }
}

使用数据注释,它可能看起来像这样:

public class CreateEmployeeViewModel : ViewModelBase
{
    [Display(Name = "First Name")]
    [Required(ErrorMessage = "First name required")]
    public string FirstName { get; set; }

    [Display(Name = "Last Name")]
    [Required(ErrorMessage = "Last name required")]
    public string LastName { get; set; }
}

要记住的关键是,视图模型只代表您要使用的数据,没有别的。如果您有一个具有 30 个属性的域模型并且您只想更新一个值,您可以想象所有不必要的代码和验证。鉴于这种情况,您将在视图模型中只有一个值/属性,而不是域对象中的所有属性。

一个视图模型可能不仅有来自一个数据库表的数据。它可以组合来自另一个表的数据。以我上面关于添加新员工记录的示例为例。除了只添加名字和姓氏之外,您可能还想添加员工的部门。此部门列表将来自您的Departments表格。因此,现在您在一个视图模型中拥有来自Employees和表的数据。Departments然后,您需要将以下两个属性添加到您的视图模型并用数据填充它:

public int DepartmentId { get; set; }

public IEnumerable<Department> Departments { get; set; }

在编辑员工数据(已经添加到数据库中的员工)时,它与我上面的示例没有太大区别。创建一个视图模型,例如调用它EditEmployeeViewModel。在此视图模型中仅包含您要编辑的数据,例如名字和姓氏。编辑数据并单击提交按钮。我不会太担心该Id字段,因为该Id值可能在 URL 中,例如:

http://www.yourwebsite.com/Employee/Edit/3

Id它和你的名字和姓氏值一起传递到你的存储库层。

删除记录时,我通常遵循与编辑视图模型相同的路径。我也会有一个 URL,例如:

http://www.yourwebsite.com/Employee/Delete/3

当视图第一次加载时,我会使用Id3 从数据库中获取员工的数据。然后我会在我的视图/页面上显示静态文本,以便用户可以看到正在删除的员工。当用户单击“删除”按钮时,我将使用Id3 的值并将其传递给我的存储库层。您只需Id要从表中删除一条记录。

另一点,您并不真的需要每个动作的视图模型。如果它是简单的数据,那么只使用EmployeeViewModel. 如果它是复杂的视图/页面并且它们彼此不同,那么我建议您为每个视图使用单独的视图模型。

我希望这可以消除您对视图模型和域模型的任何困惑。

于 2012-06-17T20:21:52.190 回答
140

视图模型是表示特定视图中使用的数据模型的类。我们可以使用这个类作为登录页面的模型:

public class LoginPageVM
{
    [Required(ErrorMessage = "Are you really trying to login without entering username?")]
    [DisplayName("Username/e-mail")]
    public string UserName { get; set; }
    [Required(ErrorMessage = "Please enter password:)")]
    [DisplayName("Password")]
    public string Password { get; set; }
    [DisplayName("Stay logged in when browser is closed")]
    public bool RememberMe { get; set; }
}

使用此视图模型,您可以定义视图(Razor 视图引擎):

@model CamelTrap.Models.ViewModels.LoginPageVM

@using (Html.BeginForm()) {
    @Html.EditorFor(m => m);
    <input type="submit" value="Save" class="submit" />
}

和行动:

[HttpGet]
public ActionResult LoginPage()
{
    return View();
}

[HttpPost]
public ActionResult LoginPage(LoginPageVM model)
{
    ...code to login user to application...
    return View(model);
}

这会产生这个结果(屏幕是在提交表单后拍摄的,带有验证消息):

如您所见,视图模型有许多角色:

  • 视图模型通过仅包含在视图中表示的字段来记录视图。
  • 视图模型可能包含使用数据注释或 IDataErrorInfo 的特定验证规则。
  • 视图模型定义了视图的外观(对于LabelFor, EditorFor,DisplayFor助手)。
  • 视图模型可以组合来自不同数据库实体的值。
  • 您可以轻松地为视图模型指定显示模板,并使用 DisplayFor 或 EditorFor 帮助器在许多地方重用它们。

另一个视图模型及其检索示例:我们要显示基本用户数据、他的权限和用户名。我们创建了一个特殊的视图模型,它只包含必填字段。我们从数据库中检索不同实体的数据,但视图只知道视图模型类:

public class UserVM {
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool IsAdministrator { get; set; }
    public string MothersName { get; set; }
}

恢复:

var user = db.userRepository.GetUser(id);

var model = new UserVM() {
   ID = user.ID,
   FirstName = user.FirstName,
   LastName = user.LastName,
   IsAdministrator = user.Proviledges.IsAdministrator,
   MothersName = user.Mother.FirstName + " " + user.Mother.LastName
} 
于 2012-06-16T14:41:50.793 回答
92
于 2015-03-19T01:30:59.010 回答
22

如果您具有特定于视图的属性,并且与 DB/服务/数据存储无关,那么使用 ViewModel 是一个很好的做法。比如说,您想根据一个(或两个)数据库字段选中一个复选框,但数据库字段本身不是布尔值。虽然可以在模型本身中创建这些属性并将其隐藏在与数据的绑定中,但您可能不希望根据此类字段和事务的数量使模型混乱。

如果视图特定的数据和/或转换太少,您可以使用模型本身

于 2012-06-16T14:44:39.910 回答
20

我没有阅读所有帖子,但每个答案似乎都缺少一个真正帮助我“明白”的概念......

如果 Model 类似于数据库Table,那么 ViewModel 类似于数据库View - 视图通常要么从一个表返回少量数据,要么从多个表(连接)返回复杂的数据集。

我发现自己使用 ViewModels 将信息传递到视图/表单中,然后在表单回发到控制器时将该数据传输到有效模型中——这对于存储列表(IEnumerable)也非常方便。

于 2016-09-09T20:53:25.650 回答
11

视图模型 a 是一个简单的类,它可以包含多个类属性。我们使用它来继承所有必需的属性,例如我有两个类 Student 和 Subject

Public class Student
{
public int Id {get; set;}
public string Name {get; set;}
}  
Public class Subject
{
public int SubjectID {get; set;}
public string SubjectName {get; set;}
}

现在我们想在视图中显示记录学生的姓名和学科的姓名(在 MVC 中),但是不能添加多个类,例如:

 @model ProjectName.Model.Student  
 @model ProjectName.Model.Subject

上面的代码会报错...

现在我们创建一个类,可以给它起任何名字,但是这种格式“XyzViewModel”会更容易理解。是继承的概念。现在我们创建一个具有以下名称的第三个类:

public class StudentViewModel:Subject
{
public int ID {get; set;}
public string Name {get; set;}
}

现在我们在 View 中使用这个 ViewModel

@model ProjectName.Model.StudentViewModel

现在我们可以在 View 中访问 StudentViewModel 和继承类的所有属性。

于 2015-09-19T06:30:43.457 回答
11

MVC 没有视图模型:它有模型、视图和控制器。视图模型是 MVVM(模型-视图-视图模型)的一部分。MVVM 源自 Presentation Model,在 WPF 中得到普及。MVVM 中也应该有一个模型,但大多数人完全忽略了该模式的要点,他们只会有一个视图和一个视图模型。MVC 中的模型类似于 MVVM 中的模型。

在 MVC 中,该过程分为 3 个不同的职责:

  • View 负责将数据呈现给用户
  • 控制器负责页面流
  • 模型负责业务逻辑

MVC 不太适合 Web 应用程序。它是 Smalltalk 引入的一种用于创建桌面应用程序的模式。Web 环境的行为完全不同。从桌面开发中复制一个 40 年前的概念并将其粘贴到 Web 环境中没有多大意义。然而很多人认为这没问题,因为他们的应用程序编译并返回正确的值。也就是说,在我看来,不足以宣布某个设计选择是可以的。

Web 应用程序中的模型示例可能是:

public class LoginModel
{
    private readonly AuthenticationService authentication;

    public LoginModel(AuthenticationService authentication)
    {
        this.authentication = authentication;
    }

    public bool Login()
    {
        return authentication.Login(Username, Password);
    }

    public string Username { get; set; }
    public string Password { get; set; }
}

控制器可以像这样使用它:

public class LoginController
{
    [HttpPost]
    public ActionResult Login(LoginModel model)
    {
        bool success = model.Login();

        if (success)
        {
            return new RedirectResult("/dashboard");
        }
        else
        {
            TempData["message"] = "Invalid username and/or password";
            return new RedirectResult("/login");
        }
    }
}

您的控制器方法和模型将很小,易于测试且切中要害。

于 2015-12-03T16:04:21.153 回答
11

很多大的例子,让我清晰明了地解释。

ViewModel = 为视图服务而创建的模型。

ASP.NET MVC 视图不能有多个模型,因此如果我们需要将多个模型的属性显示到视图中,这是不可能的。ViewModel 服务于这个目的。

View Model 是一个模型类,它只能包含视图所需的那些属性。它还可以包含来自数据库的多个实体(表)的属性。顾名思义,这个模型是根据视图要求创建的。

下面是几个视图模型的示例

  • 要在视图页面中列出来自多个实体的数据——我们可以创建一个视图模型并拥有我们想要列出数据的所有实体的属性。加入这些数据库实体并设置视图模型属性并返回视图以一种表格形式显示不同实体的数据
  • 视图模型可能只定义视图所需的单个实体的特定字段。

ViewModel 也可用于将记录插入、更新到多个实体中,但 ViewModel 的主要用途是将来自多个实体(模型)的列显示到单个视图中。

创建 ViewModel 的方法与创建 Model 相同,为 Viewmodel 创建视图的方法与为 Model 创建视图的方法相同。

这是一个使用 ViewModel 的 List 数据的小例子。

希望这会有用。

于 2016-01-29T07:46:26.617 回答
7

ViewModel 是修补 MVC 框架概念上的笨拙的解决方法。它代表 3 层 Model-View-Controller 架构中的第 4 层。当 Model(领域模型)不合适,对于 View 来说太大(大于 2-3 个字段)时,我们创建较小的 ViewModel 将其传递给 View。

于 2017-10-03T09:03:51.657 回答
2

View Model 是我们可以用来在 View 上呈现数据的类。假设您有两个实体 Place 和 PlaceCategory,并且您想使用单个模型访问这两个实体的数据,那么我们使用 ViewModel。

  public class Place
    {
       public int PlaceId { get; set; }
        public string PlaceName { get; set; }
        public string Latitude { get; set; }
        public string Longitude { get; set; }
        public string BestTime { get; set; }
    }
    public class Category
    {
        public int ID { get; set; }
        public int? PlaceId { get; set; }
        public string PlaceCategoryName { get; set; }
        public string PlaceCategoryType { get; set; }
    }
    public class PlaceCategoryviewModel
    {
        public string PlaceName { get; set; }
        public string BestTime { get; set; }
        public string PlaceCategoryName { get; set; }
        public string PlaceCategoryType { get; set; }
    }

所以在上面的示例中 Place 和 Category 是两个不同的实体,并且 PlaceCategory 视图模型是我们可以在视图上使用的视图模型。

于 2019-01-19T07:30:28.687 回答
1

视图模型是数据的概念模型。例如,它的用途是获取子集或组合来自不同表的数据。

您可能只需要特定的属性,因此这允许您只加载那些而不是额外的不必要的属性

于 2018-09-21T09:16:41.793 回答
1
  • ViewModel 包含在视图中表示的字段(对于 LabelFor、EditorFor、DisplayFor 助手)
  • ViewModel 可以使用数据注释或 IDataErrorInfo 具有特定的验证规则。
  • ViewModel 可以有来自不同数据模型或数据源的多个实体或对象。

设计视图模型

public class UserLoginViewModel 
{ 
[Required(ErrorMessage = "Please enter your username")] 
[Display(Name = "User Name")]
[MaxLength(50)]
public string UserName { get; set; }
 [Required(ErrorMessage = "Please enter your password")]
 [Display(Name = "Password")]
 [MaxLength(50)]
 public string Password { get; set; } 
} 

在视图中呈现视图模型

@model MyModels.UserLoginViewModel 
@{
 ViewBag.Title = "User Login";
 Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm())
{
<div class="editor-label">
 @Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
 @Html.TextBoxFor(m => m.UserName)
 @Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
 @Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
 @Html.PasswordFor(m => m.Password)
 @Html.ValidationMessageFor(m => m.Password)
</div>
<p>
 <input type="submit" value="Log In" />
</p>
</div>
}

与行动一起工作

public ActionResult Login()
{ 
return View();
}
[HttpPost]
public ActionResult Login(UserLoginViewModel user)
{
// To acces data using LINQ
DataClassesDataContext mobjentity = new DataClassesDataContext();
 if (ModelState.IsValid) 
{ 
try
 {
 var q = mobjentity.tblUsers.Where(m => m.UserName == user.UserName && m.Password == user.Password).ToList(); 
 if (q.Count > 0) 
 { 
 return RedirectToAction("MyAccount");
 }
 else
 {
 ModelState.AddModelError("", "The user name or password provided is incorrect.");
 }
 }
 catch (Exception ex)
 {
 } 
 } 
 return View(user);
} 
  1. 在 ViewModel 中只放置您想要在视图/页面上显示的那些字段/数据。
  2. 由于视图代表了 ViewModel 的属性,因此易于渲染和维护。
  3. 当 ViewModel 变得更复杂时使用映射器。
于 2018-11-10T07:44:01.640 回答
1

如果您想学习如何使用 ViewModels 设置“基线”Web 应用程序的代码,我可以建议在 GitHub 上下载此代码:https ://github.com/ajsaulsberry/BlipAjax 。我开发了大型企业应用程序。当你这样做时,设置一个处理所有这些“ViewModel”功能的良好架构是有问题的。我认为使用 BlipAjax,您将拥有一个非常好的“基线”。它只是一个简单的网站,但非常简单。我喜欢他们使用英语来指出应用程序中真正需要什么的方式。

于 2019-10-09T09:53:06.513 回答
1

ViewModel 是包含要在 mvc View 中使用的字段的模型。将 ViewModel 用于视图有以下好处:

  • 由于数据库模型(实体类)包含单个表的数据。如果需要来自多个表的数据,单个 Viewmodel 可以有多个表的字段。
  • 用户不能直接与数据库模型交互,因此数据库层或模型是安全的。
  • 它用于通过存储库从数据库模型中获取数据并传递给视图。同样,它利用将数据发布到数据库模型来更新数据库记录。
于 2020-07-19T19:45:36.123 回答
0

视图模型与您的数据模型相同,但您可以在其中添加 2 个或更多数据模型类。据此,您必须更改控制器以一次采用 2 个模型

于 2020-11-24T06:36:20.600 回答