7 天玩转 ASP.NET MVC — 第 7 天(7k7k)

网友投稿 690 2022-09-12

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

7 天玩转 ASP.NET MVC — 第 7 天(7k7k)

目录

0. 前言

今天是开心的一天。因为我们终于来到了系列学习的最后一节。我相信你喜欢之前的课程,并从中学到了许多。

1. Lab 32 — 让项目有组织性

这个实验确切地讲无关任何新的功能。它只是使项目更有结构性和系统化。

第一步:创建解决方案文件夹

右击解决方案,然后选择 Add -> New Solution Folder。

将文件夹的名称改为「View And Controller」。现在重复这个步骤,创建多个相似的文件夹,分别命名为「Model」,「ViewModel」,「Data Access Layer」。

第二步:创建数据访问层项目

右击 Data Access Layer 文件夹,然后创建一个新的类库项目,命名为「DataAccessLayer」。

第三步:创建业务层和业务实体层项目

在 Model 文件夹下创建两个类库项目,分别命名为「BusinessLayer」 和 「BusinessEntities」。

第四步:创建 ViewModel 项目

在 ViewModel 文件夹下创建一个新的类库项目,命名为「ViewModel」。

第五步:添加引用

首先右击每一个项目,然后选择 Add -> Reference,选择如下引用。

对于 DataAccessLayer,选择 BusinessEntities。对于 BusinessLayer,选择 DataAccessLayer 和 BusinessEntities。对于 MVC Web Application,选择 BusinessLayer,BusinessEntities 和 ViewModel。对于 BusinessEntities,选择 System.ComponentModel.DataAnnotations。

第六步:设置项目

从 MVC 项目中的 DataAccessLayer 文件夹中复制 SalesERPDAL.cs 文件到新创建的 Data Access Layer 类库项目中。

从 MVC 项目中移除 DataAccessLayer 文件夹。从 MVC 项目的 Model 文件夹下复制 Employee.cs,UserDetails.cs 和 UserStatus.cs 文件到新创建的 BusinessEntities 类库项目中。从 MVC 项目的 Model 文件下复制 EmployeeBusinessLayer.cs 文件到新创建的 BusinessLayer 类库项目中。从 MVC 项目中移除 Model 文件夹。从 MVC 项目的 ViewModels 文件夹下复制所有类到新创建的 View Model 类库项目中。从 MVC 项目中移除 ViewModels 文件夹。将 MVC 项目,即 WebApplication1 移到「View And Controller」解决方案文件夹。

第七步:Build 项目

选择菜单栏的 Build -> Build Solution。你将会得到如下的错误信息。

第八步:解决错误

向 ViewModel 项目中添加 System.Web 引用。在 DataAccessLayer 和 BusinessLayer 项目中运用 Nuget Manager,安装 Entity Framework。(如果你对 Nuget Manager 感到困惑,建议你看一下第 3 天的课程)

注:业务层需要引用 Entity Framework 是因为 BusinessLayer 直接与 DataAccessLayer 相关联。在一个正确的架构中,业务层不应该与数据访问层直接关联。我们可以通过 Repository 来完成这个目的。

从 MVC 项目中移除 EntityFramework。

步骤如下。

第九步: Build 解决方案

你将会看到如下错误。

第十步:解决错误

现在,我们在 MVC 项目中既没有 SalesERPDAL 引用,也没有 Entity Framework 引用。添加这些引用不是一个最佳实践。作为最佳实践,控制器不应该与数据访问层直接相关联。

在 DataAccessLayer 项目中创建一个新的类,命名为 DatabaseSettings,它有一个静态方法,命名为 SetDatabase。

using System.Data.Entity;  using WebApplication1.DataAccessLayer;  namespace DataAccessLayer  {    public class DatabaseSettings    {        public static void SetDatabase()        {            Database.SetInitializer(new DropCreateDatabaseIfModelChanges());        }    }    }

在 BusinessLayer 项目中创建一个新的类,命名为 BusinessSettings,它有一个静态方法,命名为 Setbusiness。

using DataAccessLayer;namespace BusinessLayer  {    public class BusinessSettings    {        public static void SetBusiness()        {            DatabaseSettings.SetDatabase();        }    }}

在 Global.asax 中运用语句来解决错误,并且移除 Database.SetInitializer 语句。触发 BusinessSettings.SetBusiness 函数。

using BusinessLayer;  ......BundleConfig.RegisterBundles(BundleTable.Bundles);  BusinessSettings.SetBusiness();

再次 Bulid 应用,这一次将会成功。

Lab 32 的 Q&A

什么是解决方案文件夹?

Solution 文件夹只是逻辑文件夹。实际上,它不会在物理硬盘上被创建。它的目的只是为了让解决方案更加系统化。

2. Lab 33 — 创建单页应用 — Part 1 — 设置

现在,我们将不会对已存在的控制器和视图做出改变。我们将会为此实验创建一个全新的控制器和视图。做这些步骤的理由是:

正如我所说的,我们将会创建新的控制器,视图和视图模型。

只有以下组件会被重复利用。

已存在的 Business Layer。已存在的 Data Access Layer。已存在的 Business Entities。Authentication 和异常过滤器。FooterViewModel。Footer.cshtml。

第一步:创建一个新的 Area

它将在项目中创建一个新的文件夹架构,如下所示。

很明显,我们并不需要 Area 下的 Model 文件夹,删除即可。

什么是 Areas?

Areas 是实现 ASP.NET MVC 项目模块化的一种简单方式。

每一个项目都由多个模块组成。例如:账户模块,顾客关系模块,付款模块,等等。

在传统的应用开发风格中,我们经常使用「Folders」来达到这个目的。我们在一个单独项目中创建多个文件夹。每一个文件夹代表一个模块。我们会把各自模块的文件放在各自的文件夹中。

当使用 ASP.NET MVC 时,这种自定义文件夹将会遇到大问题。

让我们来讨论下在 ASP.NET MVC 中,运用简单的文件夹来实现模块。

DataAccessLayer,BusinessLayer,BusinessEntities 和 ViewModels 不会产生任何问题。他们仅仅是简单的类,所以可以被放置到任意地方。我们不能将控制器随意放置。它必须放置在 Controller 文件夹下。但是这不会成为一个大问题,因为从 MVC 4 开始,控制器的位置限制就已经被舍弃了。现在我们可以将其放置到任意想要放置的地方。不幸的是,对于视图是不可行的。所有的视图都必须放置在「~/Views/ControllerName」或者「~/Views/Shared」文件夹下。

第二步:创建所需的 ViewModels

在 ViewModel 类库项目中创建一个新的文件夹,命名为 SPA,然后创建一个 ViewModel,命名为 MainViewModel。

using WebApplication1.ViewModels;  namespace WebApplication1.ViewModels.SPA  {    public class MainViewModel    {        public string UserName { get; set; }        public FooterViewModel FooterData { get; set; }//New Property    }}

第三步:创建 Index 行为方法

在 MainController 中引用如下语句。

using WebApplication1.ViewModels.SPA;  using OldViewModel=WebApplication1.ViewModels;

在 MainController 中创建一个新的行为方法,命名为 Index。

public ActionResult Index()  {    MainViewModel v = new MainViewModel();    v.UserName = User.Identity.Name;    v.FooterData = new OldViewModel.FooterViewModel();    v.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value    v.FooterData.Year = DateTime.Now.Year.ToString();    return View("Index", v);}

正如你所见,为 WebApplication1.ViewModels 命名空间增加了一个 OldViewModels 别名。现在,我们可以使用 OldViewModel.ClassName,而不是 WebApplication1.ViewModels.ClassName。

不指定别名会导致歧义错误。在命名空间 WebApplication1.ViewModels.SPA 和 WebApplication1.ViewModels 中,存在相似的类。

第四步:创建 Index 视图

创建一个与上述 Index 方法相联系的视图。

@using WebApplication1.ViewModels.SPA@model MainViewModel        Employee Single Page Application

第五步:执行并测试应用

按下 F5,然后执行应用。完成登录操作,然后导航到 MainController 中的 Index 行为。

Lab 33 的 Q&A

为什么在控制器名称之前需要 SPA 关键字?

在我们的例子中,你可以发现名称为 SpaAreaRegistration.cs 文件,它被放置在「~/Areas/Spa」文件夹下。SpaAreaRegistration 类的 RegisterArea 方法包含如下代码。

context.MapRoute(                  "SPA_default",                "SPA/{controller}/{action}/{id}",                new { action = "Index", id = UrlParameter.Optional });

这就解释了为什么我们需要在控制器名称前添加 SPA 关键字。

SpaAreaRegistration 类中的 RegisterArea 方法如何被触发?

打开 Global.asax 文件,Application_Start 的第一行如下。

AreaRegistration.RegisterAllAreas();

RegisterAllAreas 方法查找到应用中所有来自于 AreaRegistration 的类型,并调用它们的每一个 RegisterArea 方法。

我们可以不使用 SPA 来触发 MainController 动作吗?

让我们简化一下问题:URL 为「localhost:8870/Main/Index」还会起作用吗?

答案是肯定的。AreaRegistration 类创建一个新的路由,但是不会删除其它路由。路由在 RouteConfig 类中定义,仍然起作用。正如我之前所说的那样,控制器的位置没有限制。因此它仍能起作用,但是输出不会被正确地呈现,因为它将不能查找到视图。我建议你执行一下应用,试一试。

3. Lab 34 — 创建单页应用 — Part 2 — 展示 Employees

第一步:为展示已存在的 Employees 创建 ViewModel

在 ViewModel 类库的 SPA 文件夹下创建两个新的 ViewModel 类,命名为 EmployeeViewModel 和 EmployeeListViewModel。

namespace WebApplication1.ViewModels.SPA  {    public class EmployeeViewModel    {        public string EmployeeName { get; set; }        public string Salary { get; set; }        public string SalaryColor { get; set; }    }}

namespace WebApplication1.ViewModels.SPA  {    public class EmployeeListViewModel    {        public List Employees { get; set; }    }}

注:两个 ViewModel 实际上都是 Non-Spa 应用的 ViewModel 复制品。唯一的区别是不需要 BaseViewModel 了。

第二步:创建 EmployeeList Index

在 MainController 下创建一个新的行为方法,命名为 EmployeeList。

public ActionResult EmployeeList()  {    EmployeeListViewModel employeeListViewModel = new EmployeeListViewModel();    EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();    List employees = empBal.GetEmployees();    List empViewModels = new List();    foreach (Employee emp in employees)    {        EmployeeViewModel empViewModel = new EmployeeViewModel();        empViewModel.EmployeeName = emp.FirstName + " " + emp.LastName;        empViewModel.Salary = emp.Salary.Value.ToString("C");        if (emp.Salary > 15000)        {            empViewModel.SalaryColor = "yellow";        }        else        {            empViewModel.SalaryColor = "green";        }        empViewModels.Add(empViewModel);    }    employeeListViewModel.Employees = empViewModels;    return View("EmployeeList", employeeListViewModel);}

注:HeaderFooterFilter 不再需要。

第三步:创建 AddNewLink 分部视图

这次我们不能运用之前的 AddNewLink 分部视图,因为之前的标签设定会导致全部的刷新。我们的目标是创建一个「Single Page Application」,因此我们不应该有全部的刷新。

在「~/Areas/Spa/Views/Main」文件夹下创建一个新的分部视图,命名为 AddNewLink.cshtml。

Add New

第四步:创建 AddNewLink 行为方法

在 MainController 下创建一个新的行为方法,命名为 GetAddNewLink。

public ActionResult GetAddNewLink()  {if (Convert.ToBoolean(Session["IsAdmin"]))  {return PartialView("AddNewLink");  }else  {return new EmptyResult();  }}

第五步:创建 EmployeeList 视图

在「~/Areas/Spa/Views/Main」文件夹下创建一个新的分部视图,命名为 EmployeeList。

@using WebApplication1.ViewModels.SPA@model EmployeeListViewModel

      @{        Html.RenderAction("GetAddNewLink");    }            Employee Name

第六步:设置 EmployeeList 为初始页

在「~/Areas/Spa/Views/Main」文件夹下打开 Index.cshtml 文件,在 DivOptions div 中包含 EmployeeList 行为结果。

第七步:执行并测试

按下 F5,并执行应用。

4. Lab 35 — 创建单页应用 — Part 3 — 创建 Employee

第一步:创建 AddNew 视图模型

在 ViewModel 类库项目的 SPA 文件夹下创建一个新的视图模型,命名为 CreateEmployeeViewModel。

namespace WebApplication1.ViewModels.SPA  {    public class CreateEmployeeViewModel    {        public string FirstName { get; set; }        public string LastName { get; set; }        public string Salary { get; set; }    }}

第二步:创建 AddNew 行为方法

using WebApplication1.Filters;

在 MainController 下创建 AddNew 行为方法如下。

[AdminFilter]public ActionResult AddNew()  {    CreateEmployeeViewModel v = new CreateEmployeeViewModel();    return PartialView("CreateEmployee", v);}

第三步:创建 CreateEmployee 分部视图

在「~/Areas/Spa/Views/Main」文件夹下创建一个新的分部视图,命名为 CreateEmployee。

@using WebApplication1.ViewModels.SPA@model CreateEmployeeViewModel

                          

第四步:引入 JQuery UI

右击项目,然后选择「Manage Nuget Manager」。搜索「JQuery UI」。

第五步:包含 JQuery UI

打开「~/Areas/Spa/Views/Main/Index.cshtml」文件,然后包含 JQuery.js,JQueryUI.js 和 All.css 文件。这些文件作为 JQuery UI 的一部分被 Nuget Manager 所添加。

    

在 JavaScript 中,「JavaScript 对象」用于呈现复杂数据。看一下如下例子。

var e={  EmpName= "Sukesh",  Address= "Mumbai"  };

将复杂的数据从 .NET 传输给其它技术,意味着类对象从 .NET 传输给其它技术,将复杂数据从 JavaScript 传输给其它技术,意味着 JavaScript 对象从 JavaScript 传输给其它技术。

直接传输是不可能的。按照之前的标准,我们先要将 .NET 对象或者 JavaScript 对象转换为字符串类型,然后再发送。

解决方案:一个统一的数据格式标准

就像之前一样,行业也指出一个统一的数据格式标准。说它是统一的,意味着所有人要发送数据之前都需要呈现出他们的数据。因此 XML 应运而生。

所有技术都将数据转换为 XML 格式,然后将其发送给其它技术。就像字符串一样,XML 也被当做一种标准格式,因此每一个技术都知道它。

C# 代码创建的 Employee 对象也能通过 XML 格式这样呈现。

          Sukesh      

Mumbai

因此解决方案是,「技术1把复杂的数据转换为 XML 格式的字符串数据,然后将其传送给技术2」。

问题 — XML 格式的问题

XML 格式有如下的问题。

XML 格式增加了需要发送的字符串大小。大小越大,意味着转化需要更多的时间,即意味着更差的性能。第二个原因,也是最主要的原因:XML 很难创建和解析。

让我们来探讨一下。

正如我们之前所说,每一个技术都需要基于数据创建 XML 字符串,然后传输这个 XML 字符串。现在利用 XML Serializers,用 C# 基于 .NET 对象来创建 XML 字符串是容易的。但是对于 JavaScript 而言呢?实际上, JavaScript 既没有序列化的概念,也没有 XML 操作库用于使用。因此当 JavaScript 传输数据给其它技术时,我们需要在 JavaScript 对象中手动创建 XML 字符串。这是一个很艰难的任务。当一个技术从另一个技术那里接收到数据时,通常都是 XML 格式的字符串。现在通过 XML Deserializers,用 C# 将 XML 字符串解析并创建 .NET 对象是容易的。但是对于 JavaScript 而言呢?实际上, JavaScript 既没有反序列化的概念,也没有 XML 操作库用于使用。因此当 JavaScript 解析 XML 字符串时,这是一个很艰难的任务。

解决方案 — JSON

为了解决 XML 格式带来的问题,行业想出一个新的格式,称为 JSON。它是 「JavaScript Object Notation」的缩写。

利用 C# 来创建 Employee 对象,可以通过如下代码来呈现 JSON 格式。

{  EmpName: "Sukesh",  Address: "Mumbai"}

JSON 格式展现的数据和 JavaScript 对象相像,因此这种格式被命名为 JSON(JavaScript Object Notation)。

正如你所看见的,这比之前更轻量级。有一些完备的函数可用于 JavaScript,即能将 JavaScript 对象转换为 JSON 格式字符串,也能将 JSON 格式字符串解析为 JavaScript 对象。

如下代码展示了如何创建和解析 JSON 字符串。

var e={  EmpName= “Sukesh”,  Address= “Mumbai”  };var EmployeeJsonString = JSON.stringify(e);//This EmployeeJsonString will be send to other technologies.var EmployeeJsonString=GetFromOtherTechnology();  var e=JSON.parse(EmployeeJsonString);  alert(e.EmpName);  alert(e.Address);

关闭对话框

我们可以运用 JQuery API 来关闭 CreateEmployee 对话框。

更新 Grid

可以通过如下方式来更新 Grid。

通过分部视图

a. 像 CreateEmployee 设计函数一样,创建一个 Grid 的分部视图。

b. 在 EmployeeListView 中创建一个含有 Id 的 Div,然后在里面展示 Grid 的分部视图。

我相信迄今为止我们完成的任何一个实验都能给你一个很好的思路来实现这样的目的,因此我们将把其作为一个任务。需要你来亲自完成它。

通过手动代码

在这个方法中,MVC 行为方法将会返回 EmployeeViewModel,而不是 EmloyeeListViewModel,这将会被 JavaScript 接收并运用 JavaScript 来创建一个新的行,然后手动插入到 Grid 中。EmployeeViewModel 将会以 JSON 字符串形式来从 MVC 行为方法中传输到 JavaScript。

回到实验

第十步:创建 SaveEmployee Action

在 MainController 中创建一个新的行为方法,命名为 SaveEmployee。

[AdminFilter]public ActionResult SaveEmployee(Employee emp)  {    EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();    empBal.SaveEmployee(emp);EmployeeViewModel empViewModel = new EmployeeViewModel();  empViewModel.EmployeeName = emp.FirstName + " " + emp.LastName;  empViewModel.Salary = emp.Salary.Value.ToString("C");  if (emp.Salary > 15000)  {empViewModel.SalaryColor = "yellow";  }else  {empViewModel.SalaryColor = "green";      }return Json(empViewModel);  }

现在使用 JSON 的方式来讲字符串从 MVC 行为方法传输到 JavaScript。

第十一步:包含 Validation.js

在上述实验中包含 Validation.js 文件。

@using WebApplication1.ViewModels.SPA@model CreateEmployeeViewModel

第十二步:创建 SaveEmployee 函数

打开 CreateEmployee.cshtml 视图,在顶部创建 SaveEmployee 函数。

......    function SaveEmployee() {        if (IsValid()) {            var e =                {                    FirstName: $('#TxtFName').val(),                    LastName: $('#TxtLName').val(),                    Salary: $('#TxtSalary').val()                };            $.post("/SPA/Main/SaveEmployee",e).then(                function (r) {                    var newTr = $('

');                    var nameTD = $('');                    var salaryTD = $('');                    nameTD.text(r.EmployeeName);                    salaryTD.text(r.Salary);                     salaryTD.css("background-color", r.SalaryColor);                    newTr.append(nameTD);                    newTr.append(salaryTD);                    $('#EmployeeTable').append(newTr);                    $('#DivCreateEmployee').dialog('close');                 }                );        }    }

第十三步:执行并测试

按下 F5,执行应用。

Lab 35 的 Q&A

JSON 方法是用于做什么的?

JSONResult 是 ActionResult 的一个子类。在第六天的学习中,我们谈到了 MVC  请求周期。现在我们再来回顾一下。

它将会创建 ViewPageActivator 类的对象。它将会选择正确的 ViewEngine,将 ViewPageActivator 对象作为参数传输给 ViewEngine 的构造器。ViewEngine 将会创建 View 类的对象。它将会触发视图的 RenderView 方法,用于渲染最终 HTML 输出的响应。

当它来自于 JsonResult,ExecuteResult 方法将会:

设置响应内容的类型为「Application/Json」。运用 JavaScript Serializer,它将会把传输的数据转换为 JSON 格式的字符串。为响应流书写最终的 JSON 格式字符串。

5. Lab 36 — 创建单页应用 — Part 4 — 批量上传

第一步:创建 SpaBulkUploadController

创建一个新的 AsyncController,称作 SpaBulkUploadController。

namespace WebApplication1.Areas.SPA.Controllers  {    public class SpaBulkUploadController : AsyncController    {    }}

第二步:创建 Index 方法

在上述的控制器中创建一个新的行为方法,称为 Index。

[AdminFilter]public ActionResult Index()  {    return PartialView("Index");}

第三步:创建 Index 分部视图

在「~/Areas/Spa/Views/SpaBulkUpload」中创建一个新的分部视图,称为 Index。

      Select File :     

第四步:创建 OpenBulkUpload 方法

在「~/Areas/Spa/Views/Main」文件夹中打开 Index.cshtml,然后创建一个 JavaScript 方法,称为 Index.cshtml。

function OpenBulkUpload() {              $.get("/SPA/SpaBulkUpload/Index").then                (                    function (r) {                        $("").html(r).dialog({ width: 'auto', height: 'auto', modal: true, title: "Create New Employee",                            close: function () {                                $('#DivBulkUpload').remove();                            } });                    }                );        }        

第五步:执行并测试

第六步:创建 FileUploadViewModel

在 ViewModel 类库项目的 SPA 文件夹下创建一个新的视图模型类,称为 FileUploadViewModel。

namespace WebApplication1.ViewModels.SPA  {    public class FileUploadViewModel    {        public HttpPostedFileBase fileUpload { get; set; }    }}

第七步:创建 Upload 行为

在 SpaBulkUploadController 下创建一个新的行为方法,称为 Upload。

[AdminFilter]public async Task Upload(FileUploadViewModel model)  {    int t1 = Thread.CurrentThread.ManagedThreadId;    List employees = await Task.Factory.StartNew>        (() => GetEmployees(model));    int t2 = Thread.CurrentThread.ManagedThreadId;    EmployeeBusinessLayer bal = new EmployeeBusinessLayer();    bal.UploadEmployees(employees);    EmployeeListViewModel vm = new EmployeeListViewModel();    vm.Employees = new List();    foreach (Employee item in employees)    {        EmployeeViewModel evm = new EmployeeViewModel();        evm.EmployeeName = item.FirstName + " " + item.LastName;        evm.Salary = item.Salary.Value.ToString("C");        if (item.Salary > 15000)        {            evm.SalaryColor = "yellow";        }        else        {            evm.SalaryColor = "green";        }        vm.Employees.Add(evm);    }    return Json(vm);}private List GetEmployees(FileUploadViewModel model)  {    List employees = new List();    StreamReader csvreader = new StreamReader(model.fileUpload.InputStream);    csvreader.ReadLine();// Assuming first line is header    while (!csvreader.EndOfStream)    {        var line = csvreader.ReadLine();        var values = line.Split(',');//Values are comma separated        Employee e = new Employee();        e.FirstName = values[0];        e.LastName = values[1];        e.Salary = int.Parse(values[2]);        employees.Add(e);    }    return employees;}

正如你所看见的,这次我们返回的是 JsonResult,而不是重定向。

第八步:创建 Upload 函数

在「~/Areas/Spa/Views/SpaBulkUpload」文件夹下打开 Index 视图。然后创建一个 JavaScript 函数,称为 Upload。

第九步:执行并测试

创建一个文本文件,如下所示。

按下 F5,并执行应用。

6. 总结

这里,我们完成了 7 天玩转 ASP.NET MVC 的系列学习。我们已经运用 ASP.NET MVC 的功能完成了一个简单的项目。我们也在其中穿插讨论了许多详细的理论概念。

学无止境,虽然 ASP.NET MVC 的系列学习已经告终,但是后续的深入学习,还需要靠脚踏实地,不断地实践和反思。

希望每一个人都享受其中,乐于学习,不断成长。

上一篇:Celery 和 Redis 入门(celery框架)
下一篇:Oracle 全球副总裁林元宏加盟 应用性能管理第一品牌(oracle存储过程)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~

                First Name: