七天学会ASP.NET MVC(七)——创建单页应用

2017-01-10 10:03:15来源:oschina作者:乐搏学院人点击


实验32 ———整理项目组织结构

实验32与其他实验不同,本实验并不是在之前实验基础之上为程序添加新的功能,实验32主要目的是整理项目结构,使项目条理清晰,能够结构化系统化,便于其他人员理解。


1. 创建解决方案文件夹


右键单击,选择“新解决方案文件夹—>添加—>新解决方案”,命名为“View And Controller”


重复上述步骤 ,创建文件夹“Model”,“ViewModel”,”Data Access Layer”



2. 创建数据访问层工程


右击“Data Access Layer”文件夹,新建类库“DataAccessLayer”。


3. 创建业务层和业务实体项


在Model文件夹下创建新类库“BusinessLayer”和“BusinessEntities”


4. 创建ViewModel 项


在ViewModel 文件夹下新建类库项“ViewModel“


5. 添加引用


为以上创建的项目添加引用,如下:


1. DataAccessLayer 添加 BusinessEntities项


2. BusinessLayer 添加DataAccessLayer和 BusinessEntities项


3. MVC WebApplication 选择 BusinessLayer,BusinessEntities, ViewModel


4. BusinessEntities 添加 System.ComponentModel.DataAnnotations


6. 设置


1.将DataAccessLayer文件夹下的 SalesERPDAL.cs文件,复制粘贴到新创建的 DataAccessLayer 类库中。


2. 删除MVC项目(WebApplication1)的DataAccessLayer文件夹 3. 同上,将Model文件夹中的 Employee.cs, UserDetails.cs 及 UserStatus.cs文件复制到新建的 BusinessEntities文件夹中。


4. 将MVC项目中的Model文件夹的 EmployeeBusinessLayer.cs文件粘贴到新建的 BusinessLayer的文件夹中。


5. 删除MVC中的Model文件夹


6. 将MVC项目的ViewModels文件夹下所有的文件复制到新建的ViewModel 类库项中。


7. 删除ViewModels文件夹


8. 将整个MVC项目剪切到”View And Controller”解决方案文件夹中。

7. Build


选择Build->Build Solution from menu bar,会报错。



8. 改错


1. 给ViewModel项添加System.Web 引用


2. 在DataAccessLayer 和 BusinessLayer中使用Nuget 管理,并安装EF(Entity Framework)(如果对于Nuget的使用有不理解的地方可以查看第三篇博客文章)


注意:在Business Layer中引用EF 是非常必要的,因为Business Layer与DataAccessLayer 直接关联的,而完善的体系架构它自身的业务层是不应该与DataAccessLayer直接关联,因此我们必须使用pattern库,协助完成。


3. 删除MVC 项目中的EF

右击MVC 项目,选择”Manage Nuget packages“选项


在弹出的对话框中选择”Installed Packages“


则会显示所有的已安装项,选择EF,点解卸载。

9. 编译会发现还是会报错



10. 修改错误


报错是由于在项目中既没有引用 SalesERPDAL,也没有引用EF,在项目中直接引用也并不是优质的解决方案。


1. 在DataAccessLayer项中 新建带有静态方法”SetDatabase“的类”DatabaseSettings“


1:usingSystem.Data.Entity;
2:usingWebApplication1.DataAccessLayer;
3:namespaceDataAccessLayer
4:{
5:publicclassDatabaseSettings
6:{
7:publicstaticvoidSetDatabase()
8:{
9:Database.SetInitializer(newDropCreateDatabaseIfModelChanges());
10:}
11:}
12:}

2. 在 BusinessLayer项中新建带有”SetBusiness“ 静态方法的”BusinessSettings“类。


1:usingDataAccessLayer;
2:
3:namespaceBusinessLayer
4:{
5:publicclassBusinessSettings
6:{
7:publicstaticvoidSetBusiness()
8:{
9:DatabaseSettings.SetDatabase();
10:}
11:}
12:}

3. 删除global.asax 中的报错的Using语句 和 Database.SetInitializer 语句。 调用 BusinessSettings.SetBusiness 函数:


1:usingBusinessLayer;
2:.
3:.
4:.
5:BundleConfig.RegisterBundles(BundleTable.Bundles);
6:BusinessSettings.SetBusiness();

再次编译程序,会发现成功。


关于实验32

什么是解决方案文件夹?


解决方案文件夹是逻辑性的文件夹,并不是在物理磁盘上实际创建,这里使用解决方案文件夹就是为了使项目更系统化更有结构。


实验33——创建单页应用 1—安装

实验33中,不再使用已创建好的控制器和视图,会创建新的控制器及视图,创建新控制器和视图原因如下:


1. 保证现有的选项完整,也会用于旧版本与新版本对比 2. 学习理解ASP.NETMVC 新概念:Areas


接下来,我们需要从头开始新建controllers, views,ViewModels。


下面的文件可以被重用:

已创建的业务层


已创建的数据访问层


已创建的业务实体


授权和异常过滤器


FooterViewModel


Footer.cshtml


1. 创建新Area


右击项目,选择添加->Area,在弹出对话框中输入SPA,点击确认,生成新的文件夹,因为在该文件夹中不需要Model中Area的文件夹,删掉。




接下来我们先了解一下Areas的概念


Areas


Areas是实现Asp.NetMVC 项目模块化管理的一种简单方法。


每个项目由多个模块组成,如支付模块,客户关系模块等。在传统的项目中,采用“文件夹”来实现模块化管理的,你会发现在单个项目中会有多个同级文件夹,每个文件夹代表一个模块,并保存各模块相关的文件。


然而,在Asp.net MVC 项目中使用自定义文件夹实现功能模块化会导致很多问题。


下面是在Asp.Net MVC中使用文件夹来实现模块化功能需要注意的几点:

DataAccessLayer, BusinessLayer, BusinessEntities和ViewModels的使用不会导致其他问题,在任何情况下,可视作简单的类使用。


Controllers—只能保存在Controller 文件夹,但是这不是大问题,从MVC4开始,控制器的路径不再受限。现在可以放在任何文件目录下。


所有的Views必须放在“~/Views/ControllerName” or “~/Views/Shared”文件夹。


2. 创建必要的ViewModels


在ViewModel类库下新建文件夹并命名为SPA,创建ViewModel,命名为”MainViewModel“,如下:


1:usingWebApplication1.ViewModels;
2:namespaceWebApplication1.ViewModels.SPA
3:{
4:publicclassMainViewModel
5:{
6:publicstringUserName{get;set;}
7:publicFooterViewModelFooterData{get;set;}//NewProperty
8:}
9:}

3. 创建Index action 方法


在 MainController 中输入:


1:usingWebApplication1.ViewModels.SPA;
2:usingOldViewModel=WebApplication1.ViewModels;

在MainController 中新建Action 方法,如下:


1:publicActionResultIndex()
2:{
3:MainViewModelv=newMainViewModel();
4:v.UserName=User.Identity.Name;
5:v.FooterData=newOldViewModel.FooterViewModel();
6:v.FooterData.CompanyName="StepByStepSchools";//Canbesettodynamicvalue
7:v.FooterData.Year=DateTime.Now.Year.ToString();
8:returnView("Index",v);
9:}

usingOldViewModel=WebApplication1.ViewModels 这行代码中,给WebApplication1.ViewModels 添加了别名OldViewModel,使用时可直接写成OldViewModel.ClassName这种形式。


如果不定义别名的话,会产生歧义,因为WebApplication1.ViewModels.SPA 和 WebApplication1.ViewModels下有名称相同的类。


4.创建Index View


创建与上述Index方法匹配的View


1:@usingWebApplication1.ViewModels.SPA
2:@modelMainViewModel
3:
4:
5:
6:
7:
8:EmployeeSinglePageApplication

5. 运行测试



关于实验33

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


在ASP.NET MVC应用中添加area时,Visual Studio会自动创建并命名为“[AreaName]AreaRegistration.cs”的文件,其中包含了AreaRegistration的派生类。该类定义了 AreaName属性和用来定义register路劲信息的 RegisterArea 方法。


在本次实验中你会发现nameSpaArealRegistration.cs文件被存放在“~/Areas/Spa”文件夹下,SpaArealRegistration类的RegisterArea方法的代码如下:


1:context.MapRoute(
2:"SPA_default",
3:"SPA/{controller}/{action}/{id}",
4:new{action="Index",id=UrlParameter.Optional}
5:);

这就是为什么一提到Controllers,我们会在Controllers前面加SPA关键字。


SPAAreaRegistration的RegisterArea方法是怎样被调用的?


打开global.asax文件,首行代码如下:


1:AreaRegistration.RegisterAllAreas();

RegisterAllAreas方法会找到应用程序域中所有AreaRegistration的派生类,并主动调用RegisterArea方法


是否可以不使用SPA关键字来调用MainController?


AreaRegistration类在不删除其他路径的同时会创建新路径。RouteConfig类中定义了新路径仍然会起作用。如之前所说的,Controller存放的路径是不受限制的,因此它可以工作但可能不会正常的显示,因为无法找到合适的View。


实验34——创建单页应用2—显示Employees

1.创建ViewModel,实现“显示Empoyee”功能


在SPA中新建两个ViewModel 类,命名为”EmployeeViewModel“及”EmployeeListViewModel“:


1:namespaceWebApplication1.ViewModels.SPA
2:{
3:publicclassEmployeeViewModel
4:{
5:publicstringEmployeeName{get;set;}
6:publicstringSalary{get;set;}
7:publicstringSalaryColor{get;set;}
8:}
9:}

1:namespaceWebApplication1.ViewModels.SPA


2:{
3:publicclassEmployeeListViewModel
4:{
5:publicListEmployees{get;set;}
6:}
7:}
8:

注意:这两个ViewModel 都是由非SPA 应用创建的,唯一的区别就在于这次不需要使用BaseViewModel。


2. 创建EmployeeList Index


在MainController 中创建新的Action 方法”EmployeeList“action 方法


1:publicActionResultEmployeeList()
2:{
3:EmployeeListViewModelemployeeListViewModel=newEmployeeListViewModel();
4:EmployeeBusinessLayerempBal=newEmployeeBusinessLayer();
5:Listemployees=empBal.GetEmployees();
6:
7:ListempViewModels=newList();
8:
9:foreach(Employeeempinemployees)
10:{
11:EmployeeViewModelempViewModel=newEmployeeViewModel();
12:empViewModel.EmployeeName=emp.FirstName+""+emp.LastName;
13:empViewModel.Salary=emp.Salary.Value.ToString("C");
14:if(emp.Salary>15000)
15:{
16:empViewModel.SalaryColor="yellow";
17:}
18:else
19:{
20:empViewModel.SalaryColor="green";
21:}
22:empViewModels.Add(empViewModel);
23:}
24:employeeListViewModel.Employees=empViewModels;
25:returnView("EmployeeList",employeeListViewModel);
26:}
27:

注意: 不需要使用 HeaderFooterFilter


3. 创建AddNewLink 分部View


之前添加AddNewLink 分部View已经无法使用,因为Anchor标签会造成全局刷新,我们的目标是创建”单页应用“,因此不需要全局刷新。


在”~/Areas/Spa/Views/Main“ 文件夹新建分部View”AddNewLink.cshtml“。


1:AddNew

4. 创建AddNewLinkAction 方法


在MainController中创建 ”GetAddNewLink“ action 方法。


1:publicActionResultGetAddNewLink()
2:{
3:if(Convert.ToBoolean(Session["IsAdmin"]))
4:{
5:returnPartialView("AddNewLink");
6:}
7:else
8:{
9:returnnewEmptyResult();
10:}
11:}

5. 新建EmployeeListView


在“~/Areas/Spa/Views/Main”中创建新分部View 命名为“EmployeeList”。


1:@usingWebApplication1.ViewModels.SPA
2:@modelEmployeeListViewModel
3:

4:@{
5:Html.RenderAction("GetAddNewLink");
6:}
7:
8:
9:
10:EmployeeName

6. 设置EmployeeList为初始页面


打开“~/Areas/Spa/Views/Main/Index.cshtml”文件,在Div标签内包含EmployeeList action结果。


1:...
2:

7. 运行



实验 35——创建单页应用3—创建Employee

1. 创建AddNew ViewModels


在SPA中新建 ViewModel类库项的ViewModel,命名为“CreateEmployeeViewModel”。


1:namespaceWebApplication1.ViewModels.SPA
2:{
3:publicclassCreateEmployeeViewModel
4:{
5:publicstringFirstName{get;set;}
6:publicstringLastName{get;set;}
7:publicstringSalary{get;set;}
8:}
9:}

2. 创建AddNew action 方法


在MainController中输入using 语句:


1:usingWebApplication1.Filters;

在MainController 中创建AddNew action 方法:


1:[AdminFilter]
2:publicActionResultAddNew()
3:{
4:CreateEmployeeViewModelv=newCreateEmployeeViewModel();
5:returnPartialView("CreateEmployee",v);
6:}

3. 创建CreateEmployee分部View


在“~/Areas/Spa/Views/Main”中创建新的分部View“CreateEmployee”


1:@usingWebApplication1.ViewModels.SPA
2:@modelCreateEmployeeViewModel
3:

4:
5:
6:

4. 添加jQueryUI


右击项目选择“Manage Nuget Manager”。找到“jQueryUI”并安装。



项目中会自动添加.js和.css文件



5. 在项目中添加jQueryUI


打开“~/Areas/Spa/Views/Main/Index.cshtml”,添加jQuery.js,jQueryUI.js 及所有的.css文件的引用。这些文件会通过Nuget Manager添加到jQuery UI 包中。


1:
2:
3:
4:
5:EmployeeSinglePageApplication
6:
7:...

6. 实现OpenAddNew方法


在“~/Areas/Spa/Views/Main/Index.cshtml”中新建JavaScript方法“OpenAddNew”。


1:

7. 运行


完成登录步骤后导航到Index中,点击Add New 链接。



8. 创建ResetForm方法


在CreateEmployee.cshtml顶部,输入以下代码,创建ResetForm函数:


1:@modelCreateEmployeeViewModel
2:

9. 创建CancelSave 方法


在CreateEmployee.cshtml顶部,输入以下代码,创建CancelSave 函数:


1:document.getElementById('TxtSalary').value="";
2:}
3:functionCancelSave(){
4:$('#DivCreateEmployee').dialog('close');
5:}

在开始下一步骤之前,我们先来了解我们将实现的功能:

最终用户点击保存按钮


输入值必须在客户端完成验证


会将合法值传到服务器端


新Employee记录必须保存到数据库中


CreateEmployee对话框使用完成之后必须关闭


插入新值后,需要更新表格。

为了实现三大功能,先确定一些实现计划:


1.验证


验证功能可以使用之前项目的验证代码。


2.保存功能


我们会创建新的MVC action 方法实现保存Employee,并使用jQuery Ajax调用


3. 服务器端与客户端进行数据通信


在之前的实验中,使用Form标签和提交按钮来辅助完成的,现在由于使用这两种功能会导致全局刷新,因此我们将使用jQuery Ajax方法来替代Form标签和提交按钮。


寻求解决方案

1. 理解问题


大家会疑惑JavaScript和Asp.NET 是两种技术,如何进行数据交互?


解决方案: 通用数据类型


由于这两种技术都支持如int,float等等数据类型,尽管他们的存储方式,大小不同,但是在行业总有一种数据类型能够处理任何数据,称之为最兼容数据类型即字符串类型。


通用的解决方案就是将所有数据转换为字符串类型,因为无论哪种技术都支持且能理解字符串类型的数据。


问题:复杂数据该怎么传递?


.net中的复杂数据通常指的是类和对象,这一类数据,.net与其他技术传递复杂数据就意味着传类对象的数据,从JavaScript给其他技术传的复杂类型数据就是JavaScript对象。因此是不可能直接传递的,因此我们需要将对象类型的数据转换为标准的字符串类型,然后再发送。


解决方案—标准的通用数据格式


可以使用XML定义一种通用的数据格式,因为每种技术都需要将数据转换为XML格式的字符串,来与其他技术通信,跟字符串类型一样,XML是每种技术都会考虑的一种标准格式。


如下,用C#创建的Employee对象,可以用XML 表示为:


1:
2:Sukesh
3:
Mumbai

4:

因此可选的解决方案就是,将技术1中的复杂数据转换为XML格式的字符串,然再发送给技术2.



然而使用XML格式可能会导致数据占用的字节数太多,不易发送。数据SiZE越大意味着性能越低效。还有就是XML的创建和解析比较困难。


为了处理XML创建和解析的问题,使用JSON格式,全称“JavaScript Object Notation”。


C#创建的Employee对象用JSON表示:


1:{
2:EmpName:"Sukesh",
3:Address:"Mumbai"
4:}

JSON数据是相对轻量级的数据类型,且JAVASCRIPT提供转换和解析JSON格式的功能函数。


1:vare={
2:EmpName=“Sukesh”,
3:Address=“Mumbai”
4:};
5:varEmployeeJsonString=JSON.stringify(e);//ThisEmployeeJsonStringwillbesendtoothertechnologies.
1:varEmployeeJsonString=GetFromOtherTechnology();
2:vare=JSON.parse(EmployeeJsonString);
3:alert(e.EmpName);
4:alert(e.Address);

数据传输的问题解决了,让我们继续进行实验。


10. 创建SaveEmployeeaction


在MainController中创建action,如下:


1:[AdminFilter]
2:publicActionResultSaveEmployee(Employeeemp)
3:{
4:EmployeeBusinessLayerempBal=newEmployeeBusinessLayer();
5:empBal.SaveEmployee(emp);
6:
7:EmployeeViewModelempViewModel=newEmployeeViewModel();
8:empViewModel.EmployeeName=emp.FirstName+""+emp.LastName;
9:empViewModel.Salary=emp.Salary.Value.ToString("C");
10:if(emp.Salary>15000)
11:{
12:empViewModel.SalaryColor="yellow";
13:}
14:else
15:{
16:empViewModel.SalaryColor="green";
17:}
18:returnJson(empViewModel);
19:}

上述代码中,使用Json方法在MVC action方法到JavaScript之间传Json字符串。


11. 添加Validation.js引用


1:@usingWebApplication1.ViewModels.SPA
2:@modelCreateEmployeeViewModel
3:

12. 创建SaveEmployee方法


在CreateEmployee.cshtml View中,创建 SaveEmployee方法:


1:...
2:...
3:
4:functionSaveEmployee(){
5:if(IsValid()){
6:vare=
7:{
8:FirstName:$('#TxtFName').val(),
9:LastName:$('#TxtLName').val(),
10:Salary:$('#TxtSalary').val()
11:};
12:$.post("/SPA/Main/SaveEmployee",e).then(
13:function(r){
14:varnewTr=$('
');
15:varnameTD=$('');
16:varsalaryTD=$('');
17:
18:nameTD.text(r.EmployeeName);
19:salaryTD.text(r.Salary);
20:
21:salaryTD.css("background-color",r.SalaryColor);
22:
23:newTr.append(nameTD);
24:newTr.append(salaryTD);
25:
26:$('#EmployeeTable').append(newTr);
27:$('#DivCreateEmployee').dialog('close');
28:}
29:);
30:}
31:}
32:

13. 运行



关于实验35

JSON 方法的作用是什么?


返回JSONResult,JSONResult 是ActionResult 的子类。在第六篇博客中讲过MVC的请求周期。



ExecuteResult是ActionResult中声明的抽象方法,ActionResult所有的子类都定义了该方法。在第一篇博客中我们已经讲过ViewResult 的ExecuteResult方法实现的功能,有什么不理解的可以翻看第一篇博客。


实验36——创建单页应用—4—批量上传

1. 创建SpaBulkUploadController


创建新的AsyncController“ SpaBulkUploadController”


1:namespaceWebApplication1.Areas.SPA.Controllers
2:{
3:publicclassSpaBulkUploadController:AsyncController
4:{
5:}
6:}

2. 创建Index Action


在步骤1中的Controller中创建新的Index Action 方法,如下:


1:[AdminFilter]
2:publicActionResultIndex()
3:{
4:returnPartialView("Index");
5:}

3. 创建Index 分部View


在“~/Areas/Spa/Views/SpaBulkUpload”中创建 Index分部View


1:

2:SelectFile:
3:
4:

4. 创建 OpenBulkUpload 方法


打开“~/Areas/Spa/Views/Main/Index.cshtml”文件,新建JavaScript 方法OpenBulkUpload


1:functionOpenBulkUpload(){
2:$.get("/SPA/SpaBulkUpload/Index").then
3:(
4:function(r){
5:$("").html(r).dialog({width:'auto',height:'auto',modal:true,title:"CreateNewEmployee",
6:close:function(){
7:$('#DivBulkUpload').remove();
8:}});
9:}
10:);
11:}
12:
13:
14:
15:

5. 运行



6. 新建FileUploadViewModel


在ViewModel SPA文件夹中新建View Model”FileUploadViewModel”。


1:namespaceWebApplication1.ViewModels.SPA
2:{
3:publicclassFileUploadViewModel
4:{
5:publicHttpPostedFileBasefileUpload{get;set;}
6:}
7:}

7. 创建Upload Action


1:[AdminFilter]
2:publicasyncTaskUpload(FileUploadViewModelmodel)
3:{
4:intt1=Thread.CurrentThread.ManagedThreadId;
5:Listemployees=awaitTask.Factory.StartNew>
6:(()=>GetEmployees(model));
7:intt2=Thread.CurrentThread.ManagedThreadId;
8:EmployeeBusinessLayerbal=newEmployeeBusinessLayer();
9:bal.UploadEmployees(employees);
10:EmployeeListViewModelvm=newEmployeeListViewModel();
11:vm.Employees=newList();
12:foreach(Employeeiteminemployees)
13:{
14:EmployeeViewModelevm=newEmployeeViewModel();
15:evm.EmployeeName=item.FirstName+""+item.LastName;
16:evm.Salary=item.Salary.Value.ToString("C");
17:if(item.Salary>15000)
18:{
19:evm.SalaryColor="yellow";
20:}
21:else
22:{
23:evm.SalaryColor="green";
24:}
25:vm.Employees.Add(evm);
26:}
27:returnJson(vm);
28:}
29:
30:privateListGetEmployees(FileUploadViewModelmodel)
31:{
32:Listemployees=newList();
33:StreamReadercsvreader=newStreamReader(model.fileUpload.InputStream);
34:csvreader.ReadLine();//Assumingfirstlineisheader
35:while(!csvreader.EndOfStream)
36:{
37:varline=csvreader.ReadLine();
38:varvalues=line.Split(',');//Valuesarecommaseparated
39:Employeee=newEmployee();
40:e.FirstName=values[0];
41:e.LastName=values[1];
42:e.Salary=int.Parse(values[2]);
43:employees.Add(e);
44:}
45:returnemployees;
46:}
47:

8. 创建Upload 函数


打开”~/Areas/Spa/Views/SpaBulkUpload”的Index View。创建JavaScript函数,命名为“Upload”


1:

9. 运行




总结

七天学会MVC 就到这里结束了,谢谢大家的支持,希望大家都能够掌握所讲述的MVC知识,希望都能够进步!

登录乐搏学院官网http://www.learnbo.com/


或关注我们的官方微博微信,还有更多惊喜哦~


原文链接:http://www.codeproject.com/Articles/1010152/Learn-MVC-Project-in-Days-Day

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台

7:FirstName:
8: