我是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.

其他回答

ViewModel是包含在MVC视图中使用的字段的模型。对视图使用ViewModel有以下好处:

由于数据库模型(实体类)包含单个表的数据。如果需要来自多个表的数据,一个ViewModel可以有多个表的字段。 用户不能直接与数据库模型交互,因此数据库层或模型是安全的。 它用于通过存储库从数据库模型获取数据并将其传递给视图。类似地,它利用向数据库模型发布数据来更新数据库记录。

MVC没有视图模型:它有模型、视图和控制器。ViewModel是MVVM (Model-View-ViewModel)的一部分。MVVM派生自表示模型,在WPF中得到推广。在MVVM中也应该有一个模型,但是大多数人完全忽略了这个模式的要点,他们只有一个视图和一个视图模型。MVC中的模型与MVVM中的模型相似。

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

视图负责将数据显示给用户 控制器负责页面流 模型负责业务逻辑

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");
        }
    }
}

你的控制器方法和模型将是小的,容易测试的,并且是切中要害的。

很多大的例子,让我用一种清晰明了的方式解释。

ViewModel =为视图创建的模型。

ASP。NET MVC视图不能有多个模型,所以如果我们需要在视图中显示来自多个模型的属性,这是不可能的。ViewModel就是这个目的。

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

下面是一些视图模型的例子

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

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

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

下面是一个使用ViewModel的列表数据的小示例。

希望这对你有用。

编辑:我在我的博客上更新了这个答案:

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!
}

视图模型是一个类,我们可以使用它在视图上呈现数据。假设您有两个实体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 ViewModel是我们可以在View上使用的ViewModel。