《ASP.NET MVC 5 高级编程(第5版)》
第1章、入门
本章主要内容:
- ASP.NET MVC 5概述
- 其应用程序的创建方法
- 其应用程序的及结构
概述:将MVC设计模式应用于ASP.NET框架
ASP.NET 1.0支持两层抽象:
System.Web.UI:Web Forms层,由服务器控件和ViewState等组成。
System.Web:管道程序,提供基本的Web堆栈,包括组件模块、处理程序和HTTP堆栈。
MVC模式简介:MVC将UI分为三个主要部分:
- 模型:一组类,描述了要处理的数据及修改和操作数据的业务规则
- 视图:一组.cshtml,定义UI的显示方式
- 控制器:一组类,用于处理来自用户、整个应用程序流以及特定程序逻辑的通信
第2章、控制器
本章主要内容:
- 控制器的角色
- 例程:MVC Music Store
- 控制器基础
控制器如何响应HTTP请求并将处理的信息返回给浏览器?控制器和控制器操作的功能?
控制器主要负责响应用户的输入,同时修改模型。——>程序流、输入数据的处理和对相关视图提供输出数据。
URL首先告知路由机制实例化哪个控制器,调用哪个操作方法,并为该方法提供参数。——>然后控制器的方法决定使用哪个视图,并对该视图渲染。(MVC是方法调用结果,而非动态生成(脚本生成)页面。
例程:MVC Music Store下载地址:http://mvcmusicstore.codeplex.com/(涵盖了构建一个ASP.NET MVC程序的基本知识)。
第4章、模型
4.2为商店管理器构造基架
4.2.1基架的含义:
用模板创建M、V、C代码,这个代码生成的过程就成为“基架”,即生成CRUD功能的样板代码。通过基架,可以检测模型类的定义(决定了后面的名字),然后生成控制器以及关联的视图,有时还有数据访问类;基架决定生成代码有怎样的功能、这些类如何放置以使程序正常工作。个人认为类似于MFC类向导。
基架选项:NuGet库全是运用特定设计模式和技术来生成代码的基架(基架库)——>所以可以自定义、修改基架,也可以通过NuGet搜索scaffolder,查找基架。
右击Controllers文件夹,添加控制器(派生自Controller),选择MVC 5 常用基架模板(扩展基架P67):
- MVC 5 Contorller——Empty(MVC 5 控制器 - 空):这个选项将会在Controllers文件夹下添加一个自定义名称(弹框中自己输)的控制器类。此时该类只有Index方法:返回一个Veiw(),即一个默认的ViewResult实例的视图;在Views文件夹中不会生成任何视图(因为它用默认视图)。
- MVC 5 Controller with read/write Actions(包含读/写操作的MVC 5 控制器):相对于Empty,增加了Details(int id)、Create()、Edit(int id)、Delete(int id)方法(此时和前面1的Index一样:GET),还有三个和Index不一样(在方法前面加上[HttpPost]):Create(FormCollection collection)、Edit(int id, FormCollection collection)、Delete(int id, FormCollection collection)。但是这些操作并没有任何实际意义,因为没有自己的代码和创建关联的视图。
- Web API 2 API Controller Scaffolders(泛指):添加一个继承自ApiController的控制器,可以为程序创建Web API。
- MVC 5 Controller with Views, Using Enity Framework(包含视图的控制器,并使用EF框架):生成了整套Actions的控制器以及相关视图,还生成了与数据库交互的数据上下文类(继承自DbContext)。基架会检测所选择的模型的所有属性,因为要用它们创建——>控制器、视图、数据上下文(可以新建,也可以用现有的)。
4.2.2基架和实体框架:
新建的MVC5 项目会自动包含对实体框架(EF)的引用。EF是一个对象关系映像(ORM)框架,它知道如何在关系数据库中保存.NET对象,而且还可以用LINQ查询检索那些已经保存在关系数据库中的.NET对象。基架没有要求一定要用EF,也可以用其他的ORM或数据访问库。基架更没有强制要求使用数据库(不管是不是关系型),因为可以使用任何数据访问技术或数据源来构建应用程序,如CSV(逗号分隔的文本)或采用使用了全套WS-*协议组件的Web服务。
但是EF支持数据库优先、模型优先、代码优先(MVC基架)的开发风格。代码优先:在不创建数据库模式、也不打开VS设计器的情况下,可以向SQL Server存储或检索信息;或者直接编写纯C#类,因为EF知道如何存储其实例的正确位置,这种类的属性可以都是虚拟属性virtual,虽然这不是必须的,但这样可以为EF提供一个指向纯C#类集的钩子(hook),并为EF启用了一些特性(如高效的修改跟踪机制efficient change tracking mechanism)——>所以EF知道模型属性值的修改时刻,并在这一时刻生成并执行一个SQL UPDATE语句,使这些改变与数据库保持一致。
1.关于代码优先,EF还遵照了很多约定:例如要把模型类Album的对象存储在数据库中,EF就认为是要把该数据存储在数据库中一个Albums表中;如果要存储的对象有ID属性,EF就认为这个属性就是主键值,并把这个值赋给SQL Server中对应表的自增(标识)键列;对外键关系、数据库名称也有约定:这些约定取代了以前需要给ORM的所有映像和配置。如果要用现有的数据库,那么需要提供映射元数据。
此外,还可以自定义约定:当EF的默认约定建立数据模型的方式和我们想要的不一致:以前的EF版本的解决办法是使用数据注解或FluentAPI(但是手动配置所有选项太过乏味,就选择默认约定);现有版本EF可以通过添加自定义约定覆盖主键定义,或者改变默认的表映射(以满足自己的团队命名约定),更好的是,可以创建可重用的约定类和特性(根据自己的需要精确配置),并应用到任何模型和属性上,使得开发像标准的EF一样轻松。
2.DbContext类:使用EF的代码优先方法,需要使用EF的DbContext类派生出一个数据上下文类来访问数据库,它具有多个DbSet<T>类型的属性,其中每一个T代表一个要持久保存的对象;可以把DbSet<T>想象成一个泛型列表,它知道如何在父上下文中加载和保存数据。
数据访问策略的选择:数据访问方法已经出现多种,但方法的选择依赖于应用程序的类型以及开发团队的选择。领域驱动设计(DDD)是一种团队使用的方法,可以用来处理复杂的程序。还有另一种更主要的团队开发模式——命令查询职责分离(CQRS)用来开发复杂程序。DDD和CQRS使用的很流行的设计模式包括库和工作单元设计模式。其中库设计模式的优势之一是:可以在数据访问的代码和程序其他部分之间创建一个正常边界——这个边界可以提高代码的单元测试能力(但这不是默认的基架生成代码的优势,即默认的基架不能提高单元测试能力,因为默认基架的硬编码是依赖于EF的)。
4.2.3通过基架添加控制器:
对话框Add Scaffolder—>Add Controller:填写控制器名、模型类、数据上下文类,后两者都是模型类—>这一步是选择新建数据上下文才有,点击New data context,在New Data Context对话框(需要输入访问数据库的类名,包括名称空间:必要时改变;但是要访问数据库,就需要在控制器中实例化数据上下文类)
在控制器中,方法将上下文属性对应的数据库的数据加载到列表并作为模型传递给默认视图,加载可以分为:预加载(.Include(a => a.上下文的属性)和延迟加载策略(默认策略)
?还未理解透彻——》延迟加载策略:EF根据需要来加载,即当需要时,才发送额外的查询并加载数据。预加载Include方法则可以优化/减少构建完整模型的查询次数。
代码:var albums = db.Albums.Include(a => a.Artist).Include(a => a.Genre); //延迟加载:var albums = db.Albums;
return View(albums.ToList());
4.2.4执行基架的代码:
1.用EF创建数据库:EF的代码优先会尽可能使用约定而非配置——>如果不配置从模型到数据库的表和列的具体映射,EF会使用约定创建一个数据库模式;如果在运行时不配置一个具体的数据库连接,EF会使用约定创建一个连接。
显式配置数据库连接:①向web.config文件中添加一个连接字符串②还可以按照约定,EF
不配置:EF将尝试连接SQL Server的LocalDB实例(就是连接SQL Server的本地服务器),并且查找与数据上下文类同名的数据库。此时,如果连接成功,但找不到数据库,那么EF就会创建一个数据库。在基架创建完成后,运行程序并导航到/StoreManager,就会发现EF已经在LocalDB中创建了一个名为MvcMusicStore.Models.MusicStoreDB的数据库。
2.使用数据库初始化器:
3.播种数据库:
4.3编辑专辑
4.3.1创建编辑专辑的资源:
1.模型和视图模型终极版:
2.Edit视图:
4.3.2响应编辑时的POST请求:
1.编辑happy path:
2.编辑sad path:
4.4模型绑定
4.4.1DefaultModeBinder:
4.4.2显式模型绑定: