**《ASP.NET MVC 5 网站开发之美》
========== ========== ==========
[作者] (台) demo (台) 小朱 (台) 陈传兴 (台) 王育民 (台) 陈仕杰
[出版] 清华大学出版社
[版次] 2015年09月 第1版
[印次] 2017年03月 第2次 印刷
[定价] 128.00元
========== ========== ==========
【第01章】
(P004)
目前网页前端技术非常多元化,开发者一定要选择容易自定义与修改的框架作为主要开发框架。
(P005)
Model 可翻译为数据模型, “数据模型” 用于封装与应用程序在商业逻辑上相关的数据,以及对其数据操作的处理方法。
Model 并不依赖 View 或 Controller ,也就是说 Model 不需要知道它会如何被显示或如何被应用,只需要专注于做好数据访问、定义、验证的责任即可。
在 ASP.NET MVC 中推荐使用强类型的方式设计 Model 层,才可以有效地利用内建的模型绑定 (Model Binding) 与模型验证机制。
(P007)
在项目初期设计的时候建议将用户接口层和商业逻辑层明确地分离开,后续在开发上也会比较顺手。
(P010)
开发人员可以在同一项目中增加许多核心引用。
(P011)
Single Page Application 模板只使用单一页面来呈现各种各样的内容,单一页面的数据交换依赖 JavaScript (Client) 调用 Web API (Server) 获取,所以当开发人员选择使用 Single Page Application 模板时会发现默认同时勾选 MVC 与 Web API 。
(P012)
T4 为 “Text Template Transformation Toolkit” 的缩写,是一种文字模板转换的工具,利用 T4 可以很容易地生成程序代码。
(P017)
现在网络交换数据的格式,从以往的 XML 已经渐渐转换到更省流量的 JSON 。
(P022)
NuGet 会将此项目用到的程序包记录在 packages.config 内,因此程序包还原必须依赖此配置文件,此配置文件请务必加入版本管理。
(P037)
MVC 的设置方式是后端会将指定的数据传输到前端,不管后端开发者是使用 ViewBag 、 ViewData 、 TempData 或是直接传一个 Model 到前端,默认的 DefaultModelBinder 类都会自动将名称相同的部分自动绑定。
【第02章】
(P060)
程序是由数据和算法组成的,在 MVC 应用程序中,算法由 Controller 提供,而数据当然就是由 Model 来提供。
(P061)
既然 Model 是程序外部提供的数据,也就代表了 Model 并不限于特定技术 (例如 EF) 。
(P062)
Model 不会主动与数据源沟通,而是利用一个中介层,这个中介层规定了数据源要怎么处理 Model ,包括数据源的访问和 Model 间的数据转换等,这个中介层称为 Repository (主数据资源库) , Repositpry 负责 Model 和数据源间的协调合作。
(P065)
泛型的表示法由类与类型参数 (type parameter) 所组成,以 List
泛型也可以用在属性与方法上。
(P068)
如果一个泛型类要使用两个以上的类型参数时,可以针对各个不同的类型参数设置 where 的限制,以确保类型参数是必要的。
(P074)
SQL 指令一定要用参数化查询法,否则就会出现 SQL Injection 的漏洞。
(P082)
参数化查询是目前唯一可预防 SQL Injection 漏洞的方法。
【第03章】
(P085)
LINQ 真正的威力其实并不只是 SQL 指令的终结,而是它隐含对集合对象的强大访问能力,以及为了实现 LINQ 技术而在 .NET Framework 内所添加的各种扩展能力,这些能力才是 LINQ 真正的价值所在。
(P089)
LINQ 本身的基础建设实现于 System.Linq 命名空间内,若没有使用 using 引入这个命名空间的话,所有 LINQ 功能都无法使用。
(P091)
对象初始化器 (object initializer) 允许在程序中通过声明的方式直接给对象属性进行数值的初始化,而不必刻意建立有参数的构造函数,可降低程序员维护多个构造函数的负担。
(P092)
对象初始化器可和有参数的构造函数并用。
对于数组或集合的赋值,刻意利用相似的语法来实现,不过在初始化器内所初始化的不是集合的属性,而是集合内的元素。
(P093)
匿名类型虽然好用,但它有几个麻烦的限制 :
-
匿名方法一般只会用在同一个函数内,如果要让它被其他函数共享,则必须要动用到 Reflection ,或是利用 .NET 4.0 提供的动态类型 (dynamic types) 机制;
-
匿名类型只能有属性,不可以有方法、事件或字段等;
-
两个匿名类型对象的相等 (equal) ,必须要两个对象的属性值都相等才行;
- 匿名类型的初始化只能利用对象初始化器来进行,其属性在生成后会变成只读;
基本上,只要是匿名类型就一定得使用 var 来声明,若是现有的类型则要看当时情况而定,全都用 var 来替代也是有副作用的。
(P094)
var 类型虽然好用,但也有如下限制 :
-
使用 var 类型时赋值语句的右边不可以是 null ,否则编译器无法推断出其类型;
-
var 类型只能用于局部变量的声明,不能用于全局变量、类层级的变量或是函数的返回值;
- var 类型不可用在匿名委派或是方法群组中;
编译器在程序中看到 foreach 语句时,会将它转换成对 IEnumerable
(P095)
微软提供了一个指令 yield ,它可以让程序员以只传回每个元素的方式来自动生成 IEnumerabel
(P096)
Enumerable 内所包含的 LINQ 扩展方法,都返回了 IEnumerable
Fluent Interface 具有三项特性 :
-
通过调用方法来定义对象内容;
-
对象会自我引用 (self-referential) ,且新的对象内容会和最后一个对象内容等价;
- 通过返回 void 内容 (就是 null 或不返回最后的对象内容) 或非 Fluent Interface 的对象结束;
(P097)
事件 (event) 机制均以委派为主,所以若要在类声明一个事件,则必定要声明一个委派。
委派的声明类似于抽象方法的声明,只是将 abstract 换成 delegate 而已,不需要实现,只要声明参数原型即可。
委派可以保证目标对象的实现方法必定符合委派所声明的参数规格,以及返回的数据值,所以适合在需要由目标对象实现的流程,或是需要通知 (notification) 或是 发行/订阅 (publish/subscrible) 的应用中,亦可应用于观察者模式 (Observer Pattern) 的实现。
(P098)
到了 .NET Framework 3.5 时,微软更将 delegate 指令拿掉,以 “=>” 指令来替代 delegate 。
Lambda 表达式分成三种,一种是表达式型 Lambda (Expression Lambdas) ,一种是语句型 Lambda (Statement Lambdas) ,另一种则是异步型 Lambda (Asynchronous Lambdas) 。
表达式型 Lambda 的语法很简单 : (input parameter) => expression ;
输入参数有或没有都可以,若没有可直接以 “()” 来替代,若只有一个,则可以省去小括号,但若有两个以上参数,就必须保留小括号。
当表达式有多行时,则要选择语句型 Lambda ,它的语法结构和表达式型 Lambda 相似,差别就在大括号 (input parameter) => { statements; } 。
(P099)
若语句只有一行,那么使用表达式型 Lambda 和语句型 Lambda 只有大括号的差别。
当 Lambda 表达式要用于异步操作时,可使用异步型 Lambda ,异步型 Lambda 语法基本上和表达式语句型 Lambda 相同,差异是在声明 Lambda 时要加上 async 指令,若在 Lambda 表达式本体内用到了其他异步方法时,要在调用加上 await 指令。
async 和 await 指令适用于 .NET Framework 4.5 以上的版本。
(P100)
微软在 .NET Framework 里面放入了数个委派类型,用来简化声明委派的工作,像是无事件参数的委派 EventHandler ;有事件参数的委派 EventHandler
Predicate
(P103)
除非是要重新组装数据或是编写 LINQ 语句选取数据,否则基本上用到 Select() 的机率并不高。
(P107)
GroupBy() 本身具有延迟执行的特性,而 ToLookUp() 没有。
(P111)
如果要设置多重排序条件,请务必使用 OrderBy() 加上 ThenBy() 的组合。
(P113)
在数据库查询时,为了达到最佳的性能,在数据量大时要进行分页处理 (paging) 是一件很重要的工作。
若是要在大集合内切出少量数据时,还需要有“美工刀”,这些方法的功能就是扮演着美工刀的角色 : Skip() 、 SkipWhile() 、 Take() 、 TakeWhile() 。
(P114)
Skip() 用来在集合中跳跃,让 LINQ 核心直接将游标跳到指定的位置,而不用通过 “巡航” 来移动,在大型集合中可节省不少时间。
Take() 用来传回集合中特定数量的元素,它会告知 LINQ 核心直接返回它所指定的元素数量,很适合使用于分页的功能。
(P117)
针对远程数据源,使用 Any() 来判断有无数据是较好的选择。
若是针对本地的集合 (数组、列表或字典类型等) ,则 Any() 和 Count() 几乎没有性能上的差异。
【第04章】
(P136)
当数据变动完成时,程序员只要调用 ObjectContext
(P156)
基本上,在 EF 6.0 内所有数据库的操作 (除了 Entity Client 外) 都要经由 DbContext 来进行,也就是说,若想要用程序代码操作 EF ,就必须要从 DbContext 派生自己的 Model 类。
若要定义在 EF 中使用的表格或视图表,则要在 DbContext 的派生类内定义以 DBSet
(P163)
基本上,若可以用关联来解决继承的需求,就不要使用继承。
(P170)
在商用系统中,存储过程和函数的使用十分广泛。
(P172)
无论是使用何种方式建立模型,对程序员来说,只有一个对象要关注,那就是 DbContext 类对象,所有的数据访问动作都要通过它。
DbSet
(P173)
DBContext 的查询是由 DbSet
EF 6 在对象查询的性能上做了许多改进,因此让应用程序的性能会更好。
【第05章】
(P191)
网址在 SEO 中拥有很高的比重,如果能有优秀的设计,那么网址本身就是很好的关键词。
(P206)
只要记住利用空字符串可以回到主层而明确指定 Area 名称,就可以前往各个层的 Area 内。
【第06章】
(P211)
在 ASP.NET MVC 中默认的返回 ActionResult 类型,这个 ActionResult 类型本身是一个抽象类,可以返回任何实现 ActionResult 类的类型内容,换句话说,它封装 Action 方法的结果,是 Action 方法结果的基类。
ASP.NET 目前实现了 9 种派生自 ActionResult 类的结果类型供开发者选择。
(P213)
新添加的 View 会继承 System.Web.Mvc.ViewPage 类, ViewPage 类提供许多有用的属性与方法,以帮助呈现 HTML 的输出,其中包含如 ViewData、 ViewBag、 TempData 等对象字典属性。
(P216)
调用 HTTP POST 的 Action 方法需要额外设置 HttpPost 属性,调用 HTTP GET 的 Action 方法也有 HttpGet 属性。但 ASP.NET MVC 里所有 public 修饰词的 Action 方法默认会套用 HttpGet 属性,一般不会特别设置。
(P228)
ViewData 与 ViewBag 都有一个特性,它们都无法跨 Action 方法访问,只能存在于当次的 HTTP 请求中。
(P229)
ViewData 会在 Action 方法调用 ViewPage 时自动传递过去。
dynamic 对象会略过编译时静态类型检查,而解析工作会改变在运行时进行 (有错误也要此阶段才知道) 。
(P230)
使用 ViewBag.KeyName 并将数据存储于 ViewData 的字典中。效果等同于 ViewData ,不过因为动态的关系,性能会比 ViewData 差,就操作而言,所有特性都和 ViewData 一模一样,但可以得到一个程序代码输入时的优点。
(P231)
ViewBag 属性在输入时使用 “对象.属性” 的输入方法,对于程序代码编写比字典更为直观 (而且输入更少字) 。
ViewBag 会在 Action 方法调用 ViewPage 时自动传递过去。
(P236)
ViewData 与 ViewBag 属性无法跨 Action 方法传递数据,当需要在 Action 方法之间传递数据的,可采用 TempData 属性。
(P245)
一个 ViewPage 只能声明一个 @model 关键字。
(P248)
ViewModel 应该只封装属性, ViewModel 与 View 之间最好只有一对一的关系。
只带属性的 ViewModel 类本质上是一种 Data Transfer Object (DTO , 数据传输对象) 的应用。
(P251)
运用 Tuple 对象编写读取使用的程序代码可读性不好,但可以省下不少项目中定制化的 ViewModel 类。
(P253)
ModelBinding 是一个自动化机制,主要是通过 DefaultModelBinder 类进行自动化数据转换工作。
(P254)
DefaultModelBinder 运行机制非常依赖