7 天玩转 ASP.NET MVC — 第 2 天

0. 前言

我相信在开始第 2 天的学习时,你已经顺利地完成了第 1 天的课程。html

咱们回顾一下第 1 天的主要关注点:数据库

  • 为何选择 ASP.NET MVC ?编程

  • ASP.NET Webforms 和 ASP.NET MVC 的对比安全

  • 理解 ASP.NET MVC 的 Controller 以及 Views数据结构

提醒:若是你尚未完成第 1 天的学习,最好先确保完成它。咱们的目标是在最后一天用最佳实践和最新技术方法来建立一个小的 MVC 项目。每一天的 Lab 训练中,咱们都会比以前一天增长一些实用性的功能,这样看起来会比以前的程序更趋于完美。mvc

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,测试应用。

7 天玩转 ASP.NET MVC — 第 2 天

Lab 3 的 Q&A

写 Razor 代码的过程当中,使用花括号「『{』和『}』」和不使用花括号,有什么区别?

在 lab 3 中,@emp.FirstName 可使用如下代码替换。

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

若是在 @ 后没有使用花括号,那么它仅仅是为了展现变量或者表达式的值。

为何须要强制转换?

ViewData 内部承载了一些对象。每一次增长一个新值,就会把它转换为 Object 类型。

因此每一次都须要强制转换来获取对象的值。

「@emp.FirstName @emp.LastName」的含义是什么?

这个意味着 LastName 展现在 FirstName 以后,并经过空格隔开。

若是只想使用一个 @ 关键字,能作到刚才的效果吗?

答案是确定的。经过语法 @(emp.FirstName+””+emp.LastName)。

为何在 Controller 类中要硬编码 Employee 类?

这仅仅是为了展现 demo。实际上,咱们将会在数据库,WCF ,Web Service 或者其它地方获取数据。

什么是数据库逻辑,数据访问层以及业务层?

  • 数据访问层在 ASP.NET MVC 中是一个未显示的层。实际上,它一直存在,可是在 MVC 的定义中历来没包含过它。

  • 业务层像以前所解释的,它是 Model 的一部分。

完整的 MVC 结构。

7 天玩转 ASP.NET MVC — 第 2 天

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 并测试应用程序。

7 天玩转 ASP.NET MVC — 第 2 天

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 的全部数据值。

7 天玩转 ASP.NET MVC — 第 2 天

写下以下代码来展现数据:

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

第四步:测试并输出

7 天玩转 ASP.NET MVC — 第 2 天

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 中展现不一样类型的数据。好比:显示当前登陆的用户名称和雇员数据。

咱们可使用以下两种方式实现这个问题:

  1. 向 Employee 类增长一个 UserName 属性。每一次咱们想要在视图中展现一个新数据,咱们就像 Employee 类中增长一个属性。这彷佛是不合理的,这个属性也许和 Employee 没有关联。这也违反了 SOLID 的 SRP 准则。

  2. 运用 ViewBag 或者 ViewData。这个方法咱们已经在刚才讨论了其弊端。

ViewModel 解决方案

ViewModel 是 ASP.NET MVC 应用中没有声明出的层。它适合于 Model 和 View 之间而且为 View 做为一个数据容器。

Model 和 ViewModel 的区别是什么?

Model 特指业务数据。它基于业务和数据结构建立。ViewModel 特指 View 数据。它基于视图 View 建立。

ViewModel是如何工做的?

工做原理很是简单。

  • 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 的全部需求。

  1. First Name 和 LastName 须要合并展现,因此在展现前它们应该是合并的。

  2. 使用货币形式来显示 Amount。

  3. 不一样的 Salary 展现出不一样的颜色。

  4. 当前的 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 并测试输出。

7 天玩转 ASP.NET MVC — 第 2 天

输出的结果和 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,执行应用。

7 天玩转 ASP.NET MVC — 第 2 天

Lab 7 的 Q&A

咱们能将视图的强制类型为 List 吗?

答案是确定的。咱们能够。

为何咱们要建立一个单独的类,即 EmployeeListViewModel,为何咱们不使用强类型为 List< EmployeeListViewModel > 的View 呢?

若是咱们直接运用 List,而不是使用 EmployeeListViewModel 类,会引发两个问题。

  1. 将来也许会出现展现逻辑的需求。

  2. UserName 属性。由于 UserName 和 Employees 是没有关联的。它是与一个完整的 View 相关联。

为何咱们要从 EmployeeViewModel 中移除 UserName 属性,而后把它做为EmployeeListViewModel 中的一部分呢?

UserName 对全部雇员都是同样的,若是将 UserName 的属性保留在 EmployeeViewModel 中就会增长了冗余代码,也会为增长数据的传输额外内存空间。

5. 结语

咱们已经完成了第 2 天的 MVC 学习。在第 3 天中咱们将使得项目进入下一个阶段。

让我一块儿在学习中尽情徜徉吧!

原文地址:Learn MVC Project in 7 days

7 天玩转 ASP.NET MVC — 第 1 天

本文系 OneAPM 工程师编译整理。想阅读更多技术文章,请访问 OneAPM 官方博客

相关文章
相关标签/搜索