介绍

在看这边文章时,我们相信你已经成功的完成了第一天的内容。

第一天主要集中在:

选择MVC的理由?

ASP.NET Webform 与 ASP.NET MVC的区别

了解Controller和View

注:

如果你还没有完成前一天的内容,请先去看完再过来。我们的目标是在一天结束用最好的练习和现代的方法创建一个小的MVC项目。每次新的试验都会添加新的方法到前一个实验中或者让前一个试验更加好。

第二天日程

从控制器传递到视图

实验3 - 使用ViewData

讨论实验3

实验4 - 使用ViewBag

讨论实验4

用ViewData和ViewBag的问题

实验5 - 了解强类型View

讨论实验5

了解View Model在ASP.NET MVC中的用法

ViewModel解决方案

实验6 - 实现View Model

讨论实验6

实验7 - View中的集合

讨论实验7

结论


从控制器传递到视图

在实验2中创建的view非常的静态, 在现实场景中它会现实某些动态数据。在下个实验中我们会在View中展示一些动态数据。

View会从Controller中的模型中获取数据。


模型

在ASP.NET MVC中模型表示业务数据。

实验3 - 使用ViewData

ViewData是一个字典,它将会包含在controller和view之间传递被传递的数据。Controller将会添加元素到字典中,view会从中读取出来。让我们来做个demo。

步骤 1 - 创建Model类

在Model文件夹中创建一个叫Employee的新类 :

publicclassEmployee{publicstringFirstName{get;set;}publicstringLastName{get;set;}publicintSalary{get;set;}}

步骤 2 - 在Controller中获取Model

在下面GetView方法中新建Employee 对象:

Employeeemp=newEmployee();emp.FirstName="Sukesh";emp.LastName="Marla";emp.Salary=20000;

注: 要确保把using语句放在最上边或者放在Employee类完整的限定名前.

usingWebApplication1.Models;

步骤 3 - 创建ViewData 并返回View

把Employee对象存储在下面的ViewData中:

ViewData["Employee"]=emp;returnView("MyView");

步骤 4 - 在View中展示 Employee 数据

打开MyView.cshtml.

像下面这样 从 ViewData中获取Employee 数据并展示:

<div>@{WebApplication1.Models.Employeeemp=(WebApplication1.Models.Employee)ViewData["Employee"];}<b>EmployeeDetails</b><br/>EmployeeName:@emp.FirstName@emp.LastName<br/>EmployeeSalary:@emp.Salary.ToString("C")</div>

步骤 5 - 测试查看输出

实验 3 的讨论

在写Razor code时,有 括弧(说的是"{"和"}")和没有括弧的区别?

在最新的实验中@emp.FirstName 可以用下面的code片断(snippet)替换。

@{Response.Write(emp.FirstName);}

没有括弧的可以简单的来现实变量或表达式的值.


为什么必须转换?

把对象保存在ViewData内,每次往里添加新的值,它都会装箱到对象的类型,所以在我们从中取值的时侯做拆箱是必须的.


"@emp.FirstName @emp.LastName"是什么意思?

意思是在显示FirstName后加一个空格,然后是LastName


我们可以只写一个单独的@关键字吗?

答案是肯定的,然后语法就成了:@(emp.FirstName + " "+emp.LastName)


为什么在Controller中硬编码Employee类?

只是用于做演示的目的。在现实中我们很可能会从数据库,wcf,web或者其它地方获取。


Database 逻辑/数据访问层 和业务层是如何的呢?

在ASP.NET MVC中数据访问层是不言而喻的。塔一直都在但从没有包含在MVC的定义中。

像之前解释的一样,业务层属於Model的一部分.

完整的MVC结构


实验 4 - 使用ViewBag

ViewBag是可视数据只是一个语法糖。ViewBag采用C# 4.0 动态特性并使ViewData保持动态。

步骤 1 - 创建 View bag

继续使用实验3 中 并用下面code片断替换步骤3。

ViewBag.Employee=emp;returnView("MyView");

步骤 2 - 在view中显示 EmployeeData

用下面的code片段替换步骤4中的code

<div>@{WebApplication1.Models.Employeeemp=(WebApplication1.Models.Employee)ViewBag.Employee;}http://lybing.blog.51cto.com/user_index.php?action=addblog&job=modify&tid=1746540EmployeeDetailsEmployeeName:@emp.FirstName@emp.LastNameEmployeeSalary:@emp.Salary.ToString("C")</div>

步骤 3 - 测试输出:

实验 4

我们可以用ViewBag传递和获取ViewData?

是的,我们可以,反之也可以。像我之前讲的,ViewBag是个为了动态显示数据的语法糖。


用ViewData和ViewBag的问题所在?

在Controller和View之间传递值用ViewData和ViewBag是一个很好的选择。但在真实的项目中不常这么做。我们来讨论下有什么问题.

性能问题

在ViewData内,value是object对象。在使用之前必须要转换到正确类型,这增加了额外的性能开销。


没有类型安全,没有编译时错误

如果我们在获取value时转换了错误的类型或用了错误的key,我们会得到一个运行时错误。一个好的编程实践,错误应该在编译时被很好的处理。


在数据发送和数据接收间没有合适的连接

做为一个Developer,我个人认为这个是个重要的问题。

在MVC,Controller 和View中是比较松散的联系。Controller完全不知道在View中发生了什么,并且view也不知道Controller中发生了什么。

我们可以在Controller中传递一个或多ViewData/ViewBag值。现在开发者在写View时,他/她必须要记住从controller中来的是什么。如果一个Controller和view开发者不同,那么就更加困难了。完全不可预知,会导致很多运行时问题和低效率的开发。


实验 5 - 理解强类型View

ViewData和ViewBag的这三个问题的原因是强类型。ViewData内部values的值的数据类型是Object。

如果我们可以以某种方式设置Controller和View之间需要被传递的数据的数据类型,那么问题就被解决了,这是强类型的强项。

让我们来做个demo,这次我们将会对View有更深层次的需求。如果薪水大于15000那么就被现实成***。或者绿色。

步骤 1 - 把view修改成强类型的View

添加下面语句在view的顶部

@modelWebApplication1.Models.Employee

上面的语句把我们的View变成了Employee类型

步骤 2 - 显示数据

现在在View内,简单输入@Model和dot(),然后就会得到智能提示数据Model(Employee)类的属性。

写下下面的copy来展示数据

EmployeeDetailsEmployeeName:@Model.FirstName@Model.LastName@if(Model.Salary>15000){<span>EmployeeSalary:@Model.Salary.ToString("C");</span>}else{<span>EmployeeSarlary:@Model.Salary.ToString("C")</span>}

步骤 3 - 从Controller的Action方法中传递Model数据

修改action方法为下面的code:

Employeeemp=newEmployee();emp.FirstName="Sukesh";emp.LastName="Marla";emp.Salary=20000;returnView("MyView",emp);

实验 5 的讨论

每次在View中输入完整的限定类名(Namespace.ClassName)是必须的?

不是,我们可以用下面的语句:

@usingWebApplication1.Models@modelEmployee

View必须一直是强类型吗?或者我们可以有时可以用ViewData煌ViewBag吗?

做为最好的实践,应该总是让view保持强类型。

强类型View中可以有多个Model对象吗?

不能,在真实项目中我们常常需要在一个view中的地方去展示多个model数据,我们会在下个实验中实现这样的需求.


理解ASP.NET MVC中的View Model

在实验5 中我们违反了MVC的原则。对于MVC来说,V是View,应该是纯粹的UI。它不应该包含任何类型的logic。我们做的下面三件事,违反了纯粹的MVC架构原则。

附加 First name, Last name 和做为完整姓名展示 - Logic

显示带货币的薪水 - Logic

基于value用不同的颜色来显示薪水。换句话说:基于一些值来改变HTML元素外表 - Logic

这三个问题之外的问题,会在值得讨论的地方来讨论。

有时我们想要在一个View中展示多个类似的数据。

例如 - 展示当前登录的员工信息

我们可以用下面这些方法来实现。

添加用户名属性到Employee 类 - 每次我们想要添加新数据在View中展示,添加新属性到Employee类看似不合逻辑。这个新属性可能于Employee相关也可能不相关。它同样违反SOLID的SRP原则。

使用ViewBag或ViewData - 我们已经讨论了使用这个方案的问题


ViewModel是一个解决方案

在ASP.NET MVC应用中,ViewModel是一个约定俗成的层。它用于View,Model和act之间,做为View的数据容器


Model和ViewModel的不同?

Model是一个指定数据的业务对象,是基于业务和数据结构来创建的。ViewModel是一个指定数据的View,是基于View来创建的。


它到底是怎么工作的?

很简单。

Controller处理交互作用的Logic或者简单的工作,处理用户的请求。

Controller获取一个或多个model数据。

Controller会决定哪个view做为请求最合适的响应

Controller会基于view的需求来获取数据Model,然后创建和初始化ViewModel对象

Controller会通过ViewData/ViewBag/Stongly 类型的View来传递ViewModel数据到View

Controller会返回一个View

View和ViewModel是怎么联系的?

View将会被封装成一个强类型View:ViewModel

Model和ViewModel是怎么联系的?

Model和ViewModel应该是相互独立对的。Controller将会基于一个或多个Model对象创建和实例化ViewModel对象

让我们做个小实验来更好的理解。


实验 6 - 执行ViewModel

步骤 1 - 创建文件夹

在项目中新建一个叫ViewModel的文件夹

步骤 2 - 新建Employee ViewModel

为了做这个,我们先列出对于这个view的需求:

姓和名应该被添加在之前的显示中。

总额应该和货币一起显示

薪水应该显示不同的颜色(基于value)

当前用户名同样也需要显示在view中

在ViewModels文件夹中新建一个叫EmployeeViewModel的类,像:

publicclassEmployeeViewModel{publicstringEmployeeName{get;set;}publicstringSalary{get;set;}publicstringSalaryColor{get;set;}publicstringUserName{get;set;}}

请注意:在ViewModel中,FirstName和LastName的用一个叫EmployeeName的简单属性来替代。Salary属性的数据类型是一个string并且新增了两个新的属性:SalaryColor、UserName

步骤 3 - 在view中使用View Model

在实验 5 中我们创建了Employee类型的View,转换为EmployeeViewModel

@usingWebApplication1.ViewModels@modelEmployeeViewModel

步骤 4 - 在view中显示数据

用下面的片段来替换view中的code:

publicActionResultGetView(){Employeeemp=newEmployee();emp.FirstName="Sukesh";emp.LastName="Marla";emp.Salary=20000;EmployeeViewModelvmEmp=newEmployeeViewModel();vmEmp.EmployeeName=emp.FirstName+""+emp.LastName;vmEmp.Salary=emp.Salary.ToString("C");if(emp.Salary>15000){vmEmp.SalaryColor="yellow";}else{vmEmp.SalaryColor="green";}vmEmp.UserName="Admin";returnView("MyView",vmEmp);}

步骤 5 - 测试输出

同样的结果,但是这次的view中没有包含任何的Logic


实验 6 的讨论

这意味着每个Model都要一个View Model吗?

不是,每个View会有相应的ViewModel。

这是用来练习Model和ViewModel关系的好例子吗?

不是,做为Model和ViewModel的一个好练习,应该是互相不独立,不依赖的。

我们应该总是来创建ViewModel?如果View没有包含任何的展示Logic,又想要像这样来展示Model的数据?

我们应该总是创建ViewModel。每个View应该有它自己的ViewModel,即便ViewModel中会像model一样包含同样的属性。


我们来看下这种情况:View不包含任何展示Logic并且想要像上面一样来展示Model数据。在这种情况下假定我们不创建ViewModel

会出现的问题:在未来的需求中,如果被要求在UI中添加显示新的数据 或者需要放一些展示Logic,我们可能需要全新的UI来达到目的。

所以我们最好保存最开始的版本,并创建ViewModel。在这个例子中,在最初阶段的ViewModel将会和Model很相似


实验 7 - 使用集合的View

在这个实验中,我们会在View中展示一个Employee的列表。

步骤 1 - 改变EmployeeViewModel类

从EmployeeViewModel中删除UserName属性。

publicclassEmployeeViewModel{publicstringEmployeeName{get;set;}publicstringSalary{get;set;}publicstringSalaryColor{get;set;}}

步骤 2 - 创建ViewModel集合

在ViewModel文件夹中新建一个EmployeeListViewModel的类:

publicclassEmployeeListViewModel{publicList<EmployeeViewModel>Employees{get;set;}publicstringUserName{get;set;}}

步骤 3 - 改变为强类型的View

把MyView.cshtml转换成一个EmployeeListViewModel类型

<body><div>Hello@Model.UserName<hr/><div><table><tr><th>EmployeeName</th><th>Salary</th></tr>@foreach(EmployeeViewModeliteminModel.Employees){<tr><td>@item.EmployeeName</td><td>@item.Salary</td></tr>}</table></div></div></body>

步骤 5 - 为Employee新建Business层

在这个实验中, 会把我们的项目带到下一层深度。添加Business层到项目中。在Model文件夹中新建一个EmployeeBusinessLyaer的类,并添加一个叫GetEmployees的方法

publicclassEmployeeBusinessLayer{publicList<Employee>GetEmployees(){List<Employee>employees=newList<Employee>();Employeeemp=newEmployee();emp.FirstName="johnson";emp.LastName="fernandes";emp.Salary=14000;employees.Add(emp);Employeeemp2=newEmployee();emp2.FirstName="mikefn";emp2.LastName="mike";emp2.Salary=16000;employees.Add(emp2);returnemployees;}}

步骤 6 - 通过Controller来传递数据

publicActionResultGetView(){EmployeeListViewModelemployeeListViewModel=newEmployeeListViewModel();EmployeeBusinessLayerempBal=newEmployeeBusinessLayer();List<Employee>employees=empBal.GetEmployees();List<EmployeeViewModel>empViewModels=newList<EmployeeViewModel>();foreach(Employeeempinemployees){EmployeeViewModelempViewModel=newEmployeeViewModel();empViewModel.EmployeeName=emp.FirstName+""+emp.LastName;empViewModel.Salary=emp.Salary.ToString("C");if(emp.Salary>15000){empViewModel.SalaryColor="yellow";}else{empViewModel.SalaryColor="green";}empViewModels.Add(empViewModel);}employeeListViewModel.Employees=empViewModels;employeeListViewModel.UserName="Admin";returnView("MyView",employeeListViewModel);}

步骤 7 - 输出

实验7 的讨论

View可以是List类的强类型吗?

当然可以

为什么创建分开的EmployeeListViewModel类,而不是新建一个强类型的List<EmployeeListViewModel> ?

如果我们使用List直接替换EmployeeListViewModel,那么会有两个问题。

管理将来展示的Logic

UserName属性不是关联单独的Employees。而是关联完整的View

为什么我们从EmployeeViewModel中删除UserName属性,让它成为EmployeeListViewModel中的一部分呢?

所有的Employee将会有同样的UserName属性,把UserName放在EmployeeViewModel中只是增加冗余的code,也增中了整体数据的内存存储需要.



原文:http://www.codeproject.com/Articles/897559/Learn-MVC-in-days-Day