我是ASP.NET MVC的新手。我不太理解ViewModel的目的。
什么是ViewModel?为什么在ASP.NET MVC应用程序中需要使用ViewModel?
如果能提供一个好的工作示例和解释会更好。
我是ASP.NET MVC的新手。我不太理解ViewModel的目的。
什么是ViewModel?为什么在ASP.NET MVC应用程序中需要使用ViewModel?
如果能提供一个好的工作示例和解释会更好。
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
可能不会从视图设置,它可能是自动生成的员工表。而 DateCreated
可能也会在存储过程或应用程序的服务层中设置。因此,视图模型中不需要 Id
和 DateCreated
。当查看已捕获的员工的详细信息(静态文本)时,您可能希望显示这两个属性。
加载视图/页面时,员工控制器中的创建操作方法将创建此视图模型的实例,如果需要,则填充任何字段,然后将此视图模型传递给视图/页面:
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
当视图首次加载时,我将使用Id
为3的员工数据从数据库中获取。然后,在我的视图/页面上只显示静态文本,以便用户可以看到要删除的员工是谁。当用户单击“删除”按钮时,我将仅使用3的Id
值并将其传递给我的存储库层。您只需要Id
即可从表中删除记录。
另一个要点是,并非每个操作都需要一个视图模型。如果只是简单的数据,则只使用EmployeeViewModel
就足够了。如果是复杂的视图/页面并且它们彼此不同,则建议为每个使用单独的视图模型。
希望这能澄清您对视图模型和领域模型的任何困惑。
视图模型是一个表示特定视图中使用的数据模型的类。我们可以将此类用作登录页面的模型:
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);
}
以下是结果(截图是在提交表单后带有验证消息的屏幕截图):
可以看到,视图模型具有多种角色:
另一个视图模型及其检索的示例:我们想要显示基本用户数据、他的权限和用户名。我们创建一个特殊的视图模型,其中仅包含所需字段。我们从数据库的不同实体中检索数据,但视图仅知道视图模型类:
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
}
编辑:我在我的博客上更新了这篇答案:
http://www.samwheat.com/post/The-function-of-ViewModels-in-MVC-web-development
我的答案有点长,但我认为比较View Model和其他常用模型类型很重要,以便理解它们的不同之处以及它们的必要性。
总而言之,直接回答问题:
一般来说,视图模型是一个包含呈现视图所需的所有属性和方法的对象。视图模型属性通常与数据对象(如客户和订单)相关,并且还包含与页面或应用程序本身相关的属性,例如用户名、应用程序名称等。视图模型提供了一个方便的对象,可传递给渲染引擎以创建HTML页面。使用视图模型的众多原因之一是,视图模型提供了一种单元测试特定呈现任务的方法,例如处理用户输入、验证数据、检索用于显示的数据等。
以下是实体模型(又名DTO、模型)、演示模型和视图模型的比较。
数据传输对象(DTO)又名“模型”
数据传输对象(DTO)是一个具有与数据库中的表模式相匹配的属性的类。DTO是根据其常见用途来回传输数据的名称。
DTO的特点:
数据库表通常是规范化的,因此DTO通常也是规范化的。这使它们在呈现数据方面的用途有限。但是,对于某些简单的数据结构,它们通常做得很好。
以下是DTO可能看起来像的两个示例:
public class Customer
{
public int ID { get; set; }
public string CustomerName { get; set; }
}
public class Order
{
public int ID { get; set; }
public int CustomerID { get; set; }
public DateTime OrderDate { get; set; }
public Decimal OrderAmount { get; set; }
}
演示模型
演示模型是一个实用类,用于在屏幕或报告上呈现数据。演示模型通常用于建模由多个DTO组成的复杂数据结构。演示模型通常表示数据的去规范化视图。
演示模型的特点:
演示模型根据需要和位置使用(而DTO通常与数据库模式相关联)。演示模型可以用于对整个页面、页面上的网格或下拉菜单上的网格进行建模。演示模型通常包含其他演示模型的属性。演示模型通常用于单次使用,例如在单个页面上呈现特定网格。
一个演示模型的例子:
public class PresentationOrder
{
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
public string CustomerName { get; set; }
public Decimal OrderAmount { get; set; }
public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}
视图模型
视图模型类似于展示模型,用于渲染视图的后备类。 但是,与演示模型或DTO的构造方式非常不同。 视图模型通常包含与演示模型和DTO相同的属性,因此它们经常被混淆。
视图模型的特点:
视图模型组合
如前所述,视图模型是复合对象,因为它们将应用程序属性和业务数据属性组合在单个对象上。 常用于视图模型的应用程序属性示例包括:
以下示例说明了视图模型的组合性质的重要性以及如何构建高效且可重用的视图模型。
假设我们正在编写一个Web应用程序。 应用程序设计的一项要求是在每个页面上显示页面标题,用户名和应用程序名称。 如果我们想创建一个页面来显示演示订单对象,则可以将演示模型修改如下:
public class PresentationOrder
{
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
public string CustomerName { get; set; }
public Decimal OrderAmount { get; set; }
public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}
public class PresentationOrderVM
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
// Business properties
public PresentationOrder Order { get; set; }
}
public class PresentationOrderVM
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
// Business properties
public List<PresentationOrder> Orders { get; set; }
}
从上面的两个类可以看出,我们可以将视图模型视为包含另一个演示模型作为属性的演示模型之一。顶层演示模型(即视图模型)包含与页面或应用程序相关的属性,而演示模型(属性)包含与应用程序数据相关的属性。
我们可以进一步设计并创建一个基础视图模型类,它不仅可以用于PresentationOrders,还可以用于任何其他类:
public class BaseViewModel
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
}
public class PresentationOrderVM : BaseViewModel
{
// Business properties
public PresentationOrder Order { get; set; }
}
public class PresentationOrderVM : BaseViewModel
{
// Business properties
public List<PresentationOrder> Orders { get; set; }
}
public class BaseViewModel<T>
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
// Business property
public T BusinessObject { get; set; }
}
public class PresentationOrderVM : BaseViewModel<PresentationOrder>
{
// done!
}
public class PresentationOrderVM : BaseViewModel<List<PresentationOrder>>
{
// done!
}
MyViewModel<MyPresModel>
。 - user3230660我并没有读完所有的帖子,但每个答案似乎都缺少一个真正帮助我理解的概念...
如果模型类似于数据库的表格,那么ViewModel就相当于数据库的视图 - 视图通常可以从单个表返回少量数据,也可以从多个表(联接)返回复杂的数据集。
我发现自己使用ViewModel将信息传递到视图/表单中,然后在表单提交回控制器时将数据转换为有效的Model - 对于存储Lists(IEnumerable)也非常方便。
如果您有视图特定的属性,而不是与数据库/服务/数据存储相关的属性,使用ViewModels是一个很好的做法。例如,您想要基于一个数据库字段(或两个字段)保留复选框的选择状态,但该数据库字段本身不是布尔类型。虽然可以在模型本身中创建这些属性,并将其隐藏不与数据绑定,但根据此类字段和事务的数量,您可能不想使模型变得混乱。
如果视图特定的数据和/或转换太少,您可以直接使用模型。
有很多大的例子,让我用清晰简洁的方式解释一下。
ViewModel = 为视图创建的模型。
ASP.NET MVC 视图无法拥有多个模型,因此如果我们需要在视图中显示来自多个模型的属性,则不可能。ViewModel 就是为了服务于这个目的。
View Model 是一个只能容纳那些视图所需属性的模型类。它还可以包含来自数据库中多个实体(表)的属性。顾名思义,这个模型是专门为 View 的要求而创建的。
以下是一些 View Models 的例子:
ViewModel 还可以用于向多个实体插入和更新记录,但 ViewModel 的主要用途是将多个实体(模型)的列显示在单个视图中。
创建 ViewModel 的方法与创建 Model 的方法相同,为 ViewModel 创建视图的方法与为 Model 创建视图的方法相同。
这里有一个小例子,演示了如何使用 ViewModel 列出数据。
希望这对你有用。
视图模型 a 是一个简单的类,可以包含多个类属性。我们使用它来继承所有所需的属性,例如,我有两个类:学生和课程。
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;}
}
现在我们在视图中使用这个ViewModel
@model ProjectName.Model.StudentViewModel
现在我们可以访问StudentViewModel及其继承类的所有属性。
MVC没有View Model:它有Model、View和Controller。ViewModel是MVVM(Model-View-ViewModel)的一部分。MVVM源自Presentation Model并在WPF中广泛使用。MVVM中也应该有一个Model,但大多数人完全忽略了这种模式的重点,他们只会有一个View和一个ViewModel。MVC中的Model与MVVM中的Model类似。
在MVC中,流程被分为三个不同的职责:
MVC不太适合Web应用程序。这是Smalltalk为创建桌面应用程序引入的一种模式。Web环境的行为完全不同。将40年前的概念从桌面开发中复制并粘贴到Web环境中并不太有意义。然而,很多人认为这样做没问题,因为他们的应用程序可以编译并返回正确的值。在我看来,这还不足以将某种设计选择声明为可行。
Web应用程序中Model的一个例子可能是:
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");
}
}
}
你的控制器方法和模型将会小而简洁,易于测试并且专注于要点。
ViewModel是MVC框架中修补概念笨拙的一种方法。它代表了3层模型-视图-控制器架构的第4层。当模型(领域模型)不适合或太大(超过2-3个字段)用于视图时,我们创建一个较小的ViewModel来传递给视图。
视图模型是一个类,我们可以用它来在视图上呈现数据。假设你有两个实体 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; }
}