7 天玩转 ASP.NET MVC — 第 2 天
2017-08-10 13:08 tlnshuju 阅读(195) 评论(0) 编辑 收藏 举报0. 前言
我相信在開始第 2 天的学习时,你已经顺利地完毕了第 1 天的课程。
我们回想一下第 1 天的主要关注点:
为什么选择 ASP.NET MVC ?
ASP.NET Webforms 和 ASP.NET MVC 的对照
理解 ASP.NET MVC 的 Controller 以及 Views
提醒:假设你还没有完毕第 1 天的学习,最好先确保完毕它。我们的目标是在最后一天用最佳实践和最新技术方法来创建一个小的 MVC 项目。
每一天的 Lab 训练中,我们都会比之前一天添加一些有用性的功能,这样看起来会比之前的程序更趋于完美。
1. Controller 向 View 数据传输
在 Lab 2 中,View 的创建都是偏于静态的。
然而在真实的场景中,View 展示的一般是一些动态数据。在下一个 Lab 中。我们将展示 View 中怎样动态展示数据。
View 将从 Controller 中获取以 Model 格式展示的数据。
Model
在 ASP.NET MVC 中,Model 展示的是业务数据。
Lab 3 - 使用 ViewData
ViewData 是一个字典,它存储了 Controller 传输给 View 的数据。Controller 将向 ViewData 字典加入条目,然后 View 从这个字典里读取。如今我们開始做一个 Demo 吧。
第一步:创建一个 Model 类
在 Model 目录下创建一个新的类,命名为 Employee。
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Salary { get; set; }
}
第二步:从 Controller 中获取 Model
在 GetView 方法中创建一个 Employee 对象。
Employee emp = new Employee();
emp.FirstName = "Sukesh";
emp.LastName="Marla";
emp.Salary = 20000;
注意:确保在类中使用 Using 语句将 Model 引入,否则就要在编敲代码时使用 Employee 类的全名。
using WebApplication1.Models;
第三步:创建 ViewData 并返回 View
在 ViewData 中存储 Employee 对象。
ViewData["Employee"] = emp;
return View("MyView");
第四步:在 View 中展示 Employee 数据
打开文件 MyView.cshtml。从 ViewData 中检索 Employee 数据并展示。
<div>
@{
WebApplication1.Models.Employee emp =
(WebApplication1.Models.Employee)ViewData["Employee"];
}
<b>Employee Details </b><br/>
Employee Name : @emp.FirstName@emp.LastName <br/>
Employee Salary: @emp.Salary.ToString("C")
</div>
第五步:測试输出
按下 F5,測试应用。
Lab 3 的 Q&A
写 Razor 代码的过程中。使用花括号「『{』和『}』」和不使用花括号,有什么差别?
在 lab 3 中,@emp.FirstName 能够使用下面代码替换。
@{
Response.Write(emp.FirstName);
}
假设在 @ 后没有使用花括号,那么它不过为了展示变量或者表达式的值。
为什么须要强制转换?
ViewData 内部承载了一些对象。每一次添加一个新值,就会把它转换为 Object 类型。
所以每一次都须要强制转换来获取对象的值。
「@emp.FirstName @emp.LastName」的含义是什么?
这个意味着 LastName 展示在 FirstName 之后,并通过空格隔开。
假设只想使用一个 @ keyword,能做到刚才的效果吗?
答案是肯定的。通过语法 @(emp.FirstName+””+emp.LastName)。
为什么在 Controller 类中要硬编码 Employee 类?
这不过为了展示 demo。实际上,我们将会在数据库,WCF ,Web Service 或者其他地方获取数据。
什么是数据库逻辑,数据訪问层以及业务层?
数据訪问层在 ASP.NET MVC 中是一个未显示的层。
实际上,它一直存在,可是在 MVC 的定义中从来没包括过它。
业务层像之前所解释的。它是 Model 的一部分。
完整的 MVC 结构。
Lab 4 - 使用 ViewBag
ViewBag 就像是 ViewData 的语法蜜糖。ViewBag 运用 C# 4.0 的动态特征。使得 ViewData 动态化。
ViewBag 内部运用 ViewData。
第一步:创建 View Bag
继续 Lab 3,然后用例如以下代码片段替换 Lab 3 中的第三步:
ViewBag.Employee = emp;
第二步:在 View 中展示 EmployeeData
用例如以下的代码片段替换 Lab3 中的第四步:
@{
WebApplication1.Models.Employee emp =
(WebApplication1.Models.Employee)ViewBag.Employee;
}
Employee Details
Employee Name: @emp.FirstName @emp.LastName
Employee Salary: @emp.Salary.ToString("C")
第三步:測试并输出
按下 F5 并測试应用程序。
Lab 4 的 Q&A
我们能否够传输 ViewData。然后以 ViewBag 的形式获取到?
答案是肯定的。反过来也是能够的。
就像我之前所提到过的,ViewBag 不过 ViewData 的语法蜜糖。
ViewData 和 ViewBag 的问题
ViewData 和 ViewBag 是 Controller 与 View 之间数据传输的非常好选择方式。可是在实际的项目应用中,它们之中的不论什么一个都不是最佳的实践方式。如今我们来讨论一下运用 ViewData 和 ViewBag 的缺点吧。
性能问题
ViewData 中的数据类型是 Object。
所以我们在使用之前须要进行正确的类型转换。这个操作为性能带来了额外的负担。
没有类型安全,也没有编译时的错误。
假设我们尝试将类型转换为错误的类型。或者我们在检索对象值的时候使用错误的 Key 值。我们将会在执行时出错。可是对于一个好的编程实践而言。错误应该在编译的时候就被捕获到。
在数据传输和数据接收之间没有正确的连接
作为一个开发人员,我个人觉得这是一个非常基本的问题。
在 MVC 中, Controller 和 View 彼此之间的连接是弱连接。松散的。
Controller 全然不会关心 View 之中发生了什么,同理。View 也全然不会关心 Controller 之中发生了什么。
从 Controller 中我们能够传输一个或者多个 ViewData 或者 ViewBag 值。
如今,当一个开发人员要写一个 View 时,他须要记住 Controller 将要传输什么。
假设一个 Controller 开发人员与 View 开发人员不是同一个人。那么情况将会变得更困难。由于是全然的不关心,所以这将导致开发过程的低效率,也有可能引起执行错误。
Lab 5 - 理解强类型 Views
刚才上述关于 ViewData 和 ViewBag 的三点问题能够归结于是由数据类型所引起的。
ViewData 中存储的数据类型是 「Object」。
假设以某种方式,我们能够为传输在 Controller 和 View 中的数据设置数据类型,那么问题将会迎刃而解,而这样的方式便是强类型 Views。
如今让我们做一个 Demo。这次我们将会提升 View 的需求到下一个级别层次。假设薪水大于 15000。那么那么就展示为黄颜色。否则为绿颜色。
第一步:创建强类型的 View
在 View 的顶部加上例如以下代码:
@model WebApplication1.Models.Employee
基于这条语句,使得我们的 View 成为一个类型为 Employee 的强类型视图。
第二步:展示数据
如今,在 View 中。只使用 @Model 和 Dot(.) 操作就能够智能获取 Model,即 Empolyee 的全部数据值。
写下例如以下代码来展示数据:
Employee Details
Employee Name : @Model.FirstName @Model.LastName
@if(Model.Salary>15000)
{
<span style="background-color:yellow">
Employee Salary: @Model.Salary.ToString("C")
</span>
}
else
{
<span style="background-color:green">
Employee Salary: @Model.Salary.ToString("C")
</span>
}
第三步:从 Controller 的 Action 方法传输 Model 数据
更改 Action 方法为例如以下代码片段:
Employee emp = new Employee();
emp.FirstName = "Sukesh";
emp.LastName="Marla";
emp.Salary = 20000;
return View("MyView",emp);
第四步:測试并输出
Lab 5 的 Q&A
每次在 View 中的类型声明都须要使用类的全称吗,即 Namespace.ClassName ?
答案是否定的。我们能够运用 「using」声明。
@using WebApplication1.Models
@model Employee
我们必须总是使用强类型视图吗,还是我们能够偶尔使用一下 ViewData 或者 ViewBag ?
假设想实践最佳方式,最好使用强类型视图。
我们能够为强类型视图的 View 使用多个 Model 类型吗 ?
答案是否定的。在实际项目中,当我们想要在一个视图中展示多个 Model 时,我们常常会结束在这点上。这一需求的解决方式将在下一节中讨论。
2. 理解 ASP.NET MVC 中的 View Model
在 Lab 5 中我们已经违反了 MVC 的准则。依据 MVC, V 代表的是纯粹的 UI。
它应该不包括不论什么的逻辑。
我们已经通过例如以下的三点违反了 MVC 的结构规则:
附加了 First Name 和 Last Name。而且用它们展示了全名。这属于逻辑操作。
以货币形式展示了 Salary。
这属于逻辑操作。
展示了不同工资的不同颜色。这些基于不同值的简单的操作改变了 HTML 元素的外观。这属于逻辑操作。
除了以上三点,这里另一个更值得讨论的问题点。
这一种情形是。我们想要在 View 中展示不同类型的数据。比方:显示当前登录的username称和雇员数据。
我们能够使用例如以下两种方式实现这个问题:
向 Employee 类添加一个 UserName 属性。每一次我们想要在视图中展示一个新数据,我们就像 Employee 类中添加一个属性。这似乎是不合理的,这个属性或许和 Employee 没有关联。这也违反了 SOLID 的 SRP 准则。
运用 ViewBag 或者 ViewData。这种方法我们已经在刚才讨论了其弊端。
ViewModel 解决方式
ViewModel 是 ASP.NET MVC 应用中没有声明出的层。
它适合于 Model 和 View 之间而且为 View 作为一个数据容器。
Model 和 ViewModel 的差别是什么?
Model 特指业务数据。它基于业务和数据结构创建。ViewModel 特指 View 数据。它基于视图 View 创建。
ViewModel是怎样工作的?
工作原理非常easy。
Controller 处理用户的交互逻辑。或者简单来说,处理用户请求。
Controller 获得一个或多个 Model 数据。
Controller 将决定哪个 View 为请求作出正确回应。
Controller 将会依据视图的需求从接收的 Model 数据中创建并初始化 ViewModel 对象。
Controller 将会以 ViewData/ViewBag/强类型 View 的方式传输 ViewModel 数据给 View。
Controller 将会返回 View。
View 和 ViewModel 将怎样关联?
View 将会是一个以 ViewModel 为强类型的视图。
Model 和 ViewModel 将怎样关联?
Model 和 ViewModel 彼此之间应该是独立的。Controller 将会基于一个或多个 Model 对象来创建并初始化 ViewModel 对象。
让我们做一个小的 Lab 来更好地理解它吧。
3. Lab 6 - 实现 View Model
第一步:创建一个目录
在项目中命名一个目录,命名为 ViewModels。
第二步:创建 EmployeeViewModel
为了做这一步,我们先来理清一下 View 的全部需求。
First Name 和 LastName 须要合并展示。所以在展示前它们应该是合并的。
使用货币形式来显示 Amount。
不同的 Salary 展示出不同的颜色。
当前的 User Name 也要展示在视图中。
在 ViewModels 目录下创建一个 EmployeeViewModel 类。例如以下所看到的:
public class EmployeeViewModel
{
public string EmployeeName { get; set; }
public string Salary { get; set; }
public string SalaryColor { get; set; }
public string UserName{get;set;}
}
须要注意的是,在这个 ViewModel 类中, FirstName 和 LastName 被一个属性所替代,即 EmployeeName。
而且 Salary 的数据类型是 String,除此之外,又添加了两个属性。即 SalaryColor 和 UserName。
第三步:在 View 中运用 ViewModel
在 Lab 5 中。我们将 View 强类型为 Employee。
如今将其强类型为 EmployeeViewModel。
@using WebApplication1.ViewModels
@model EmployeeViewModel
第四步:在 View 中展示数据。
使用例如以下的代码片段替换 View 中的内容:
Hello @Model.UserName
<hr />
<div>
<b> Employee Details</b><br />
Employee Name : @Model.EmployeeName <br />
<span style="background-color:@Model.SalaryColor">
Employee Salary: @Model.Salary
</span>
</div>
第五步:创建而且传输 ViewModel
在 GetView 动作方法中,获得 Model 数据,然后将其转换为 ViewModel 对象,例如以下所看到的:
public ActionResult GetView()
{
Employee emp = new Employee();
emp.FirstName = "Sukesh";
emp.LastName="Marla";
emp.Salary = 20000;
EmployeeViewModel vmEmp = new EmployeeViewModel();
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"
return View("MyView", vmEmp);
}
第六步:測试并输出
按下 F5 并測试输出。
输出的结果和 Lab 5 的一样,可是这次 View 中不再包括不论什么逻辑。
Lab 6 的 Q&A
这是否意味着,每个 Model 都会有一个 ViewModel?
答案是否定的。
其实,是每个 View 都会有一个 ViewModel。
Model 和 ViewModel 之间存在一些关联是一个好的实践方式吗?
答案是否定的。作为一个最佳实践,Model 和 ViewModel 彼此之间应该是独立的。而不是关联的。
我们须要总是创建 ViewModel 吗? 假设 View 不包括不论什么展示逻辑而且 View 只展示 Model 的数据会怎样?
我们应该总是创建 ViewModel。每个 View 都应该拥有它们自己的 ViewModel。即使 ViewModel 的属性和 Model 的属性全然一样。
假设一种情形。View 不包括展示逻辑。而且使用 Model 数据。而不是 ViewModel。
问题是,假设未来有了向 UI 添加新数据的需求,或者是展示逻辑的需求。那么我们就须要又一次规划一个 UI 了。
所以最好是我们在一開始就创建 ViewModel 以防止需求添加。在这样的情形中,ViewModel 的初始阶段差点儿和 Model 是一致的。
4. Lab 7 - View 中运用 Collection
在这一节 Lab 中。我们将在 View 中展示 Employees 的列表。
第一步:改变 EmployeeViewModel 类
从 EmployeeViewModel 类中移除 UserName 属性。
public class EmployeeViewModel
{
public string EmployeeName { get; set; }
public string Salary { get; set; }
public string SalaryColor { get; set; }
}
第二步:创建集合
在 ViewModel 目录下创建一个类,命名为EmployeeListViewModel。
public class EmployeeListViewModel
{
public List<EmployeeViewModel> Employees { get; set; }
public string UserName { get; set; }
}
第三步:更改 View 的强类型
将 MyView.cshtml 的强类型更换为 EmployeeListViewModel。
@using WebApplication1.ViewModels
@model EmployeeListViewModel
第四步:在 View 中展示全部的雇员信息。
<body>
Hello @Model.UserName
<hr />
<div>
<table>
<tr>
<th>Employee Name</th>
<th>Salary</th>
</tr>
@foreach (EmployeeViewModel item in Model.Employees)
{
<tr>
<td>@item.EmployeeName</td>
<td style="background-color:@item.SalaryColor">@item.Salary</td>
</tr>
}
</table>
</div>
</body>
第五步:为 Employee 创建 Business Layer
在这个 Lab 中。我们将会提升我们的项目到一个新级别。我们将会向项目中添加 Business Layer。在项目中创建一个新的目录,命名为 BusinessLayer,然后创建一个新的类。命名为 EmployeeBusinessLayer。该类里面包括一个方法。命名为 GetEmployees。
public class EmployeeBusinessLayer
{
public List<Employee> GetEmployees()
{
List<Employee> employees = new List<Employee>();
Employee emp = new Employee();
emp.FirstName = "johnson";
emp.LastName = " fernandes";
emp.Salary = 14000;
employees.Add(emp);
emp = new Employee();
emp.FirstName = "michael";
emp.LastName = "jackson";
emp.Salary = 16000;
employees.Add(emp);
emp = new Employee();
emp.FirstName = "robert";
emp.LastName = " pattinson";
emp.Salary = 20000;
employees.Add(emp);
return employees;
}
}
第六步:从 Controller 中传数据
public ActionResult GetView()
{
EmployeeListViewModel employeeListViewModel =
new EmployeeListViewModel();
EmployeeBusinessLayer empBal =
new EmployeeBusinessLayer();
List<employee> employees = empBal.GetEmployees();
List<EmployeeViewModel> empViewModels =
new List<EmployeeViewModel>();
foreach (Employee emp in employees)
{
EmployeeViewModel empViewModel =
new EmployeeViewModel();
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";
return View("MyView", employeeListViewModel);
}
第七步:执行并測试输出
按下 F5。执行应用。
Lab 7 的 Q&A
我们能将视图的强制类型为 List 吗?
答案是肯定的。我们能够。
为什么我们要创建一个单独的类,即 EmployeeListViewModel,为什么我们不使用强类型为 List< EmployeeListViewModel > 的View 呢?
假设我们直接运用 List,而不是使用 EmployeeListViewModel 类。会引起两个问题。
未来或许会出现展示逻辑的需求。
UserName 属性。由于 UserName 和 Employees 是没有关联的。它是与一个完整的 View 相关联。
为什么我们要从 EmployeeViewModel 中移除 UserName 属性。然后把它作为EmployeeListViewModel 中的一部分呢?
UserName 对全部雇员都是一样的。假设将 UserName 的属性保留在 EmployeeViewModel 中就会添加了冗余代码,也会为添加数据的传输额外内存空间。
5. 结语
我们已经完毕了第 2 天的 MVC 学习。在第 3 天中我们将使得项目进入下一个阶段。
让我一起在学习中尽情徜徉吧!
原文地址:Learn MVC Project in 7 days
本文系 OneAPM 工程师编译整理。OneAPM 是中国基础软件领域的新兴领军企业,能帮助企业用户和开发人员轻松实现:缓慢的程序代码和 SQL 语句的实时抓取。想阅读很多其他技术文章,请訪问 OneAPM 官方博客。