我是ASP的新手。净MVC。我在理解ViewModel的目的方面有一个问题。
什么是ViewModel,为什么我们需要一个ASP的ViewModel。NET MVC应用程序?
如果我能给出一个关于它的工作和解释的好例子,那就更好了。
我是ASP的新手。净MVC。我在理解ViewModel的目的方面有一个问题。
什么是ViewModel,为什么我们需要一个ASP的ViewModel。NET MVC应用程序?
如果我能给出一个关于它的工作和解释的好例子,那就更好了。
当前回答
If you want to study code on how to set up a "Baseline" web application with ViewModels I can advise you to download this code on GitHub: https://github.com/ajsaulsberry/BlipAjax. I developed large enterprise applications. When you do this it's problematic to set up a good architecture that handles all this "ViewModel" functionality. I think with BlipAjax you will have a very good "baseline" to start with. It's just a simple website, but great in its simplicity. I like the way they used the English language to point out what's really needed in the application.
其他回答
视图模型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和继承类的所有属性。
编辑:我在我的博客上更新了这个答案:
http://www.samwheat.com/post/The-function-of-ViewModels-in-MVC-web-development
我的回答有点长,但我认为将视图模型与其他类型的常用模型进行比较是很重要的,这样可以理解为什么它们不同,为什么它们是必要的。
总结一下,直接回答问题:
Generally speaking, a view model is an object that contains all the properties and methods necessary to render a view. View model properties are often related to data objects such as customers and orders and in addition, they also contain properties related to the page or application itself such as user name, application name, etc. View models provide a convenient object to pass to a rendering engine to create an HTML page. One of many reasons to use a view model is that view models provide a way to unit test certain presentation tasks such as handling user input, validating data, retrieving data for display, etc.
下面是实体模型的比较。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的数据组成的复杂数据结构进行建模。表示模型通常表示非规范化的数据视图。
表示模型的特点:
Are business objects – their definition is dependent on application data. Contain mostly properties. Code is typically limited to formatting data or converting it to or from a DTO. Presentation Models should not contain business logic. Often present a denormalized view of data. That is, they often combine properties from multiple DTOs. Often contain properties of a different base type than a DTO. For example, dollar amounts may be represented as strings so they can contain commas and a currency symbol. Often defined by how they are used as well as their object characteristics. In other words, a simple DTO that is used as the backing model for rendering a grid is in fact also a presentation model in the context of that grid.
表示模型是“根据需要”和“在需要的地方”使用的(而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相同的属性,因此,它们经常被混淆。
视图模型的特点:
Are the single source of data used to render a page or screen. Usually, this means that a view model will expose every property that any control on the page will need to render itself correctly. Making the view model the single source of data for the view greatly improves its capability and value for unit testing. Are composite objects that contain properties that consist of application data as well as properties that are used by application code. This characteristic is crucial when designing the view model for reusability and is discussed in the examples below. Contain application code. View Models usually contain methods that are called during rendering and when the user is interacting with the page. This code typically relates to event handling, animation, visibility of controls, styling, etc. Contain code that calls business services for the purpose of retrieving data or sending it to a database server. This code is often mistakenly placed in a controller. Calling business services from a controller usually limits the usefulness of the view model for unit testing. To be clear, view models themselves should not contain business logic but should make calls to services which do contain business logic. Often contain properties that are other view models for other pages or screens. Are written “per page” or “per screen”. A unique View Model is typically written for every page or screen in an application. Usually derive from a base class since most pages and screens share common properties.
视图模型组合
如前所述,视图模型是复合对象,因为它们组合了单个对象上的应用程序属性和业务数据属性。视图模型中常用的应用程序属性示例如下:
用于显示应用程序状态的属性,如错误消息、用户名、状态等。 用于设置控件的格式、显示、样式化或动画化的属性。 用于数据绑定的属性,如列表对象和保存用户输入的中间数据的属性。
下面的例子说明了为什么视图模型的复合性质是重要的,以及我们如何才能最好地构建一个高效且可重用的视图模型。
假设我们正在编写一个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); } }
}
这种设计可能可行,但如果我们想创建一个显示订单列表的页面呢?PageTitle、UserName和ApplicationName属性将会重复出现,并且变得难以处理。另外,如果我们想在类的构造函数中定义一些页级逻辑呢?如果我们为将要显示的每个订单创建一个实例,就不能再这样做了。
复合优于继承
下面是一种重构订单表示模型的方法,这样它就变成了一个真正的视图模型,对于显示单个PresentationOrder对象或PresentationOrder对象的集合非常有用:
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; }
}
现在我们可以像这样简化我们的PresentationOrderVM:
public class PresentationOrderVM : BaseViewModel
{
// Business properties
public PresentationOrder Order { get; set; }
}
public class PresentationOrderVM : BaseViewModel
{
// Business properties
public List<PresentationOrder> Orders { get; set; }
}
我们可以通过使BaseViewModel泛型来使它更具可重用性:
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!
}
ViewModel是一种解决MVC框架概念上的缺陷的方法。它代表了三层模型-视图-控制器体系结构中的第四层。当Model(域模型)不合适,对于View来说太大(大于2-3个字段)时,我们创建一个更小的ViewModel来传递给View。
视图模型表示希望在视图/页面上显示的数据,无论是用于静态文本还是用于可以添加到数据库(或编辑)的输入值(如文本框和下拉列表)。它与您的领域模型有所不同。它是视图的模型。
假设你有一个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; }
}
As you can see it only contains two of the properties. These two properties are also in the employee domain model. Why is this you may ask? Id might not be set from the view, it might be auto generated by the Employee table. And DateCreated might also be set in the stored procedure or in the service layer of your application. So Id and DateCreated are not needed in the view model. You might want to display these two properties when you view an employee’s details (an employee that has already been captured) as static text.
当加载视图/页面时,员工控制器中的create action方法将创建该视图模型的实例,如果需要填充任何字段,然后将该视图模型传递给视图/页面:
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个属性的域模型,而您只想更新一个值,那么您可以想象所有不必要的代码和验证。在这种情况下,视图模型中只有这个值/属性,而不是域对象中的所有属性。
A view model might not only have data from one database table. It can combine data from another table. Take my example above about adding a new employee record. Besides adding just the first and last names you might also want to add the department of the employee. This list of departments will come from your Departments table. So now you have data from the Employees and Departments tables in one view model. You will just then need to add the following two properties to your view model and populate it with data:
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从数据库中获取员工的数据。然后,我将只在视图/页面上显示静态文本,以便用户可以看到正在删除的员工。当用户单击Delete按钮时,我将只使用Id值3并将其传递给我的存储库层。只需要Id就可以从表中删除一条记录。
另一点,你并不真的需要每个操作的视图模型。如果它是简单的数据,那么只使用EmployeeViewModel就可以了。如果是复杂的视图/页面,并且它们彼此不同,那么我建议您为每个视图使用单独的视图模型。
我希望这能消除您对视图模型和域模型的任何困惑。
很多大的例子,让我用一种清晰明了的方式解释。
ViewModel =为视图创建的模型。
ASP。NET MVC视图不能有多个模型,所以如果我们需要在视图中显示来自多个模型的属性,这是不可能的。ViewModel就是这个目的。
视图模型是一个模型类,它只能保存视图所需的那些属性。它还可以包含来自数据库的多个实体(表)的属性。顾名思义,这个模型是专门为View需求创建的。
下面是一些视图模型的例子
要在视图页中列出来自多个实体的数据,可以创建一个 查看模型,并拥有我们想要的所有实体的属性 列出数据。连接这些数据库实体并设置View模型 属性,并返回到视图以显示不同的数据 一个表格形式的实体 视图模型可能只定义单个实体的特定字段 视图所需。
ViewModel还可以用于将记录插入和更新到多个实体中,但ViewModel的主要用途是将多个实体(模型)中的列显示到单个视图中。
创建ViewModel的方法与创建Model的方法相同,为ViewModel创建视图的方法与为Model创建视图的方法相同。
下面是一个使用ViewModel的列表数据的小示例。
希望这对你有用。