ViewModel这个概念不只是在在MVC模式中有,你会在很多关于MVC、MVP、MVVM的文章中见到这个说法,并且这个概念在任何技术中都有可能提到,比如ASP.NET, Silverlight, WPF, or MVC... 现在我们来讨论如何在MVC中使用它。

ASP.NET MVC ViewModel 是什么?

在一般的情况下,我们向View中传递数据的时候,都是一个Model,当有一些额外的数据的时候,我们会使用viewbag等来进行,但是我们可以使用ViewModel将这些整合在一起也就是说:ASP.NET MVC 中的ViewModel允许你将一个或者多个data model和资源整合到一个对象中去,以此使View使用model的时候得到优化,下面的图说明了ViewModel的概念:

个人认为:viewModel 就是多个Model相结合,然后渲染同一个View

使用ViewModel的目的就是让View单个的对象来进行渲染,另一方面可以减少UI展示的逻辑代码,这个是很有必要的,也就是说View唯一的任务就是渲染单个的ViewModel对象,为了让concerns之间有一个清晰的分离,解耦意味着你的程序被设计的更好,所以我们要将对数据处理的代码放在它应该在的位置,远离View、controller。

创建个ViewModel

尽管Viewmodel包含了几个实体,但是它任然只是一个类,没有什么特别的,放置它的位置可以是:

1、一个叫做ViewModels的文件夹中,这个文件夹可以放在项目的根目录中;

2、作为一个dll,我们从MVC项目中引用它;

3、放在一个分开的项目中的service layer;

而第一种方式无疑是最简单的一种,我们只需要创建一个文件夹,然后创建一个类就行了。

为了创建一个CustomerViewModel,我们要将Customer和StateDirctionary类型作为属性,来共同组建一个CustomerViewModel类,代码如下:


public class CustomerViewModel 

    public Customer Customer { get; set; } 
    public StatesDictionary States { get; set; } 
    public CustomerViewModel(Customer customer) 
    { 
        Customer = customer; 
        States = new StatesDictionary(); 
    } 

将ViewModel发送到Veiw

当然我们是从Controller开始的,将ViewModel发送到View和我们将普通的model发送到View的做法是一样的,因为ViewModel只是一个类,View不知道也不会在意model或者viewModel是从哪里来的,你可以在controller中创建一个ViewModel的实例,为了保证controller的整洁,没有额外的代码,在Controller中需要做的只是取得model或者ViewModel的值,没有其他的:


public ActionResult Edit(int id) 

     Customer customer = context.Customers.Single(x => x.Id == id); 
     var customerViewModel = new CustomerViewModel(customer); 
     return View(customerViewModel); 

然后就是view来渲染ViewModel

为了让View知道我们传过去的是哪一个对象,我们需要将@model关键字指向ViewModel,就像你在指定一个一般的model一样。

@model FourthCoffee.Web.ViewModels.CustomerViewModel

调用数据的代码:


<div class="editor-label">
   @Html.LabelFor(model => model.Customer.FirstName) 
</div>
<div class="editor-field">
   @Html.EditorFor(model => model.Customer.FirstName) 
   @Html.ValidationMessageFor(model => model.Customer.FirstName) 
</div>
@* ...View code continues rendering properties... 

使用ViewModel的小建议:

1、因为使用ViewModel时需要手动的进行映射,但是当ViewModel很复杂的时候,这个将会变得比较困难,这个时候,我们就可以是使用AutoMapper来简化简化工作,AutoMapper会让你顺畅的在ViewModel和models之间创建映射,除此之外还有:POCO Generator、EF POCO Templates

2、只把你在View上用来渲染的属性放到ViewModel中

3、用View来指导ViewModel属性的创建,这样才能更好的渲染和维护

下面是英文文档:

The concept of the ViewModel isn’t just for ASP.NET MVC, as you’ll see references to ViewModels throughout the web in articles and blog posts about the MVC, MVP, and MVVM patterns. Those posts and articles can center around any number of technologies such as ASP.NET, Silverlight, WPF, or MVC… This post will investigate ViewModels as they apply to the world of ASP.NET MVC.

What is an ASP.NET MVC ViewModel?

In ASP.NET MVC, ViewModels allow you to shape multiple entities from one or more data models or sources into a single object, optimized for consumption and rendering by the view. The below image illustrates the concept of a ViewModel:

The purpose of a ViewModel is for the view to have a single object to render, alleviating the need for UI logic code in the view that would otherwise be necessary. This means the only responsibility, or concern, of the view is to render that single ViewModel object, aiding in a cleaner separation of concerns (SoC). Concerns are distinct aspects of the application that have a particular purpose (i.e., concern), and keeping these aspects apart means your application is more organized, and the code more focused. Putting data manipulation code in its own location away from the view and controller, enforces SoC.

Using ViewModels in MVC for finer granularity and better SoC leads to more easily maintainable and testable code. Remember, unit testing is about testing small units.

Along with better coding practices, there are many business reasons demonstrating why you might consider using ViewModels:

  • Incorporating dropdown lists of lookup data into a related entity
  • Master-detail records view
  • Pagination: combining actual data and paging information
  • Components like a shopping cart or user profile widget
  • Dashboards, with multiple sources of disparate data
  • Reports, often with aggregate data

The above scenarios are common to a wide variety of applications, and deal with more complex data than basic CRUD forms-over-data page (e.g., a simple 1:1 mapping to the db table). For example, providing a list of states, and ensuring that the state that matches the state of current customer, means that you need to either provide two sets of data or a single set of customer/state data combined, as shown in the image below.

Some scenarios such as a lookup table representing states in the USA, could easily work with either ViewModels or a ViewBag/ViewData object, so there is some potential overlap at times. It’s up to the application architects and developers to decide what works best with their exact use case.

Creating a ViewModel

Although a ViewModel consists of multiple entities, at its core a ViewModel is still just a class – and one that doesn’t even inherit from anything special, as many MVC classes do.

Physically, ViewModels can exist in different locations, listed below:

  • In a folder called ViewModels that resides in the root of the project. (small apps)
  • As a .dll referenced from the MVC project (any size app)
  • In a separate project(s) as a service layer, for large applications that generate view/content specific data. (enterprise apps)

Since a ViewModel is just a class, the easiest way to get started using one is to create a new folder named ViewModels and add a new code file to it.

To create the CustomerViewModel ViewModel, add the Customer and StatesDictionary types as properties to form one CustomerViewModel class. In the example below, the CustomerViewModel class contains the newly defined properties.

public class CustomerViewModel 
{
    public Customer Customer { get; set; }
    public StatesDictionary States { get; set; }
    public CustomerViewModel(Customer customer)
    {
        Customer = customer;
        States = new StatesDictionary();
    }
}

Generally, ViewModels contain the word “ViewModel” as part of its name; however, the conventions at work here are for consistency in code readability, since other classes in MVC state their intents in their names as well (e.g., names of controllers, action methods, etc…use conventions in their names).

The StatesDictionary class is a simple Dictionary object containing two type parameters of type string. The class also contains the definitions for all the members in the Dictionary (i.e., the state data). The only property in the StatesDictionary class is the StateSelectList, which is an object that Html Helpers use with to render an HTML <select> element that displays a listing of states. The type Dictionary<string, string> in the StateSelectList property maps to the state abbreviation then state name, respectively.

public class StatesDictionary
{
    public static SelectList StateSelectList
    {
        get { return new SelectList(StateDictionary, "Value", "Key"); }
    } 
    public static readonly IDictionary<string, string> 
        StateDictionary = new Dictionary<string, string> { 
      {"Choose...",""}
    , { "Alabama", "AL" }
    , { "Alaska", "AK" }
    , { "Arizona", "AZ" }
    , { "Arkansas", "AR" }
    , { "California", "CA" }
    // code continues to add states...
    }; 
}

Data that lives in small lists and infrequently changes, like the StatesDictionary class, exists in all types of applications. In real world applications, you’ll find a variety of methods for dealing with lookup data such as a list of states – often XML files and SQL tables. You can replace the code in the StateDictionary method to use entities from Entity Framework, read data from files, or any data access code that you require.

After creating the ViewModel, the next steps are to instantiate it in a controller and return it to the view.

Getting the ViewModel to the view

Starts with the controller…

Sending a ViewModel to the view for rendering will work the same as when dealing with a model. Since it’s just a class, the view doesn’t know, and doesn’t care, where the model or ViewModel came from. You can create the instance of the ViewModel class in the controller, or resolve it if using an IoC container. Remember that just as you would do with views, you should keep controllers clean of unnecessary code, meaning that only code that fetches the model or ViewModel belongs here, and little more.

public ActionResult Edit(int id)
{
    Customer customer = context.Customers.Single(x => x.Id == id);
    var customerViewModel = new CustomerViewModel(customer);
    return View(customerViewModel);
}

Then the view renders the ViewModel…

In order for the view to know what object to use, set the @model keyword to point to the ViewModel, just like you already would with a regular model.

@model FourthCoffee.Web.ViewModels.CustomerViewModel

Because the Customer object is a property of the ViewModel, you’ll see the model.Class.Property syntax to access the ViewModel data, similar to the following line of code.

<div class="editor-label">
    @Html.LabelFor(model => model.Customer.FirstName)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Customer.FirstName)
    @Html.ValidationMessageFor(model => model.Customer.FirstName)
</div>
@* ...View code continues rendering properties... *@

Additionally, you can edit the Edit/Create views so that the DropDownList containing a list of the states will display, and display the correct state matching that of the customer.

<div class="editor-field">    
    @Html.DropDownList("state", new SelectList(StatesDictionary.StateSelectList, 
                       "Value", "Text", Model.Customer == null ? "" : Model.Customer.State))
    @Html.ValidationMessageFor(model => model.Customer.State)
</div>
As you might have noticed, using a ViewModel is just as easy as using the ViewBag or ViewData objects. ViewModels, however, provide those extra benefits like being easier to test and optimize.

Checking the results

After a user navigates to the /Customers/Edit/1 URL in the browser, the Razor view engine renders the CustomerViewModel similarly to the following screen shot.

The State DropDownList displays the states and the current state for that customer, as expected.

Digging Further into ViewModels

Because ViewModels render pre-manipulated data that no longer have those 1:1 mappings between model classes and database tables, you’ll need to do create mappings yourself. You can manually map small ViewModels, but this will quickly become burdensome when mapping larger classes, especially when working with parent-child-grandchild, multi-level, or complex data. This is where a tool such as AutoMappercomes into play. AutoMapper will let you fluently setup mappings between ViewModels and models more easily than doing so manually, orwriting your own mapper.

Here are some tips for using ViewModels:

  • Put only data that you’ll render in the ViewModel.
  • The view should direct the properties of the ViewModel, this way it fits better for rendering and maintenance.
  • Use a mapper when ViewModels become complex.

Some tools that can help assist you in generating POCOs (Plain Old CLR Objects) for models and ViewModels are:

In addition to these tools, you can use MvcScaffolding to create actions and views based on ViewModels. MvcScaffolding, invention of ASP.NET team member Steve Sanderson, gives you more power in creating CRUD, repository, unit test and other templates quickly and painlessly.

You should always prefer using a ViewModel rather than instantiating multiple models and putting that manipulation code in the controller.

Summary

ViewModels help you organize and manage data in MVC applications when you need to work with more complex data than the other objects allow. Using ViewModels gives you the flexibility to use data as you see fit. ViewModels area generally a more flexible way to access multiple data sources than models + ViewBag/ViewData objects.

MVC ViewModel的更多相关文章

  1. 如何创建Asp.net MVC ViewModel

    ASP.NET MVC View Model Patterns Since MVC has been released I have observed much confusion about how ...

  2. MVC 中的 ViewModel

    此文章总结自:http://rachelappel.com/use-viewmodels-to-manage-data-amp-organize-code-in-asp.net-mvc-applica ...

  3. 仿花田:内部相亲网站 意中人(Asp.net MVC,Bootstrap2)

    起因: 那是七月份了,看见单身的同事在上花田网,当时觉得风格比较清新,还没有世纪佳缘等那些网站那么商业化,加上又看到了bootrstrap,于是就想做个demo出来玩玩.中间自己又在做其他的事情,和w ...

  4. ASP.NET controller TO view 数据传递

    https://stackify.com/viewbag/ In the case of ASP.NET MVC, you have three ways to pass data from the ...

  5. 探讨mvc下linq多表查询使用viewModel的问题

    最近在开发mvc3的时候发现了一个问题,就是如何在view页面显示多表查询的数据,最简单的办法就是使用viewmodel了,以下本人使用viewmodel来实现多表查询的3中方法, 先贴代码再说: 1 ...

  6. MVC到底使用哪种方式传递Model,在ViewData、ViewBag、PartialView、TempData、ViewModel、Tuple之间取舍

    在"MVC控制器传递多个Model到视图,使用ViewData, ViewBag, 部分视图, TempData, ViewModel, Tuple"中,体验了使用不同的方式传递多 ...

  7. MVC控制器传递多个Model到视图,使用ViewData, ViewBag, 部分视图, TempData, ViewModel, Tuple

    从控制器传递多个Model到视图,可以通过ViewData, ViewBag, PartialView, TempData, ViewModel,Tuple等,本篇逐一体验.本篇源码在github. ...

  8. MVC MVVM Knockout viewmodel 提交 完整过程,包含序列化 JSON 和 字典模型绑定

    //JSON 通用操作------------------------------------------------------------------------------using Syste ...

  9. ASP.NET MVC 学习笔记之 MVC + EF中的EO DTO ViewModel

    EO: Entity Object 就是EF中的实体类, 对EO的操作会对数据库产生影响. DTO: Data Transfer Object 数据传输对象.用于在各层之间传递数据的普通类,DTO有哪 ...

随机推荐

  1. Apache Spark源码走读之22 -- 浅谈mllib中线性回归的算法实现

    欢迎转载,转载请注明出处,徽沪一郎. 概要 本文简要描述线性回归算法在Spark MLLib中的具体实现,涉及线性回归算法本身及线性回归并行处理的理论基础,然后对代码实现部分进行走读. 线性回归模型 ...

  2. Ubuntu中搭建Nginx+PHP环境最简单的方法

    先安装: sudo apt-get install nginx php5-fpm 然后编辑配置文件: sudo gedit /etc/nginx/site-available/default 找到lo ...

  3. Yii源码阅读笔记(十一)

    controller类的render部分,用于渲染视图和布局文件: /** * Returns all ancestor modules of this controller. * 获取当前控制器所有 ...

  4. 【IOS笔记】Resource Management in View Controllers

    Resource Management in View Controllers 视图控制器的资源管理 View controllers are an essential part of managin ...

  5. [转]EF 4.1 Code First

    这篇文章介绍Code First开发以及如何与DbContext API一起使用.Code First允许使用C#或VB.NET类定义模型,在类或属性上有选择性的执行额外的配置或者使用Fluent A ...

  6. Web Storage事件无法触发

    不管是在同源其他页面还是在本页面都不能触发storage事件. <!DOCTYPE html> <html> <head> <meta charset=&qu ...

  7. RESTful 架构理解

    REST中的关键词: 1.资源 2.资源的表述 3.状态转移 资源: "资源",可以是一段文本.一张图片.一首歌曲.一种操作.你可以用一个URI(统一资源定位符)指向它,每种资源对 ...

  8. Linq&Lumbda

    var y = from model in list.Where(s=>s.product==product||product=="")                    ...

  9. C#访问url地址并返回数据

    public partial class Form1 : Form { static bool isSelect = false; public Form1() { InitializeCompone ...

  10. 流媒体学习三-------SIP消息结构详解

    SIP消息由三部分组成,即:开始行(start line).消息头(header).正文(body)Start-line:请求行Request-line  消息为 request消息时使用reques ...