ASP.NET MVC是一个建立在ASP.NET平台上基于MVC模式的Web开发框架,它提供了一种与Web Form完全不同的开发方式。ASP.NET Web Form借鉴了Windows Form基于控件和事件注册的编程模式,使Web应用的开发变得简单而快捷,但是它却使开发人员与Web的本质渐行渐远。ASP.NET MVC是一种回归,它使开发人员可以真正地面向Web进行编程,我们面对的不再是拖拉到Web页面的控件,而是整个HTTP请求和响应的流程。
这不是一本传统意义上的入门书籍
在《ASP .NET MVC 4框架揭秘》出版之后,读者通过多种渠道将他们对本书的看法、建议和意见反馈给笔者。有一些读者觉得本书对他们来说太“深”了,因为他们希望买到的是一本单纯的入门书籍,所以我不得不再次强调——“这不是一本传统意义上的入门书籍”。如果你之前根本没有接触过ASP.NET MVC,并且希望有一本书能够让你在一两个星期内掌握ASP.NET MVC 的基本编程模式,那么笔者觉得选择本书并不是明智的。
笔者个人认为掌握ASP.NET MVC具有3个层次。了解基本的编程模式,掌握Controller和View的定义方式,知道路由如何注册及验证规则如何定义,此为第一层次。第二层次要求我们对ASP.NET MVC框架本身从请求接收到响应回复的整个流程有一个清晰的认识,这包括请求如何被路由、目标Controller如何被激活、Model元数据如何被解析、Action方法如何被执行、View如何呈现等。ASP.NET MVC本身是一个极具可扩展的开发框架,合理利用其扩展性可以解决很多开发中的实际问题,而掌握ASP.NET MVC的最高层次就是凭着对框架本身的运行机制的了解准确地找到相应的扩展点,并创建相应的扩展来解决我们遇到的问题。
本书不是一本ASP.NET MVC入门书籍,而是一本让处于第一层次的读者快速进入第二和第三层次的书。如果你具有进入更高层次的需求,并且有充裕的时间来阅读,笔者坚信你一定能够通过此书获得其他同类书籍难以提供的东西。
不少人觉得本书过于“深入”,但笔者个人宁愿说本书“走得更远”。虽然本书比其他同类书籍更加近距离地触摸到了ASP.NET MVC 框架的内核,但就其内容本身来说,笔者认为本书并没有什么“深不可测”的东西。尽管本书不是一本纯粹意义上的入门书籍,但是笔者绝不会根据读者个人的技术水平将其排除在本书的读者范围之外。如果读者具有基本的.NET方面的知识储备,并且从事过简单的Web开发,阅读本书不会有太大的障碍。
这是一本讲述ASP.NET MVC框架本质的书
很多.NET开发人员都在抱怨微软开发技术过快的更新频率让他们无所适从,其实他们看到的只是单纯的版本升级而已,一些本质的东西一直是“稳定”的。微软推出.NET战略已经十多年了,CLR却只有4个版本而已。最新版本的ASP.NET虽然表面上已经看不到太多最初的影子,但是整个请求处理的管道一直未曾改变。对于一项开发技术,只要我们了解了它最根本性的一些东西,不但不应该惧怕其高频率的版本更替,而应该热烈拥抱它。本书力求将关于ASP.NET MVC框架最根本的东西带给大家,而不是罗列一些简单的编程技巧。
这本书与《ASP .NET MVC 4框架揭秘》有何不同
本书针对最新版本的ASP.NET MVC ,所以ASP.NET MVC 5提供的新特性和对ASP.NET MVC 4现有特性的改变自然体现在本书之中。通过微软“官方”渠道发布的信息我们知道,“特性路由”和“认证过滤器”是ASP.NET MVC 5提供的两个新特性,我们在本书中会通过单独的章节(第13章“特性路由”)来对特性路由作详细讲解,针对认证过滤器的介绍则放到新增加的一章(第12章“过滤器”)中。
除了这些通过官方渠道了解到的改变之外,其实微软在ASP.NET MVC 5框架内部作了很多的改进,这些东西只有当我们深入去分析其源码时才有可能发现。这些“不为人知”的内容也包含在本书之中,如果你手中正好有一本《ASP.NET MVC 4框架揭秘》,在阅读的时候对照一下就知道了。
本书除了反映ASP.NET MVC 5本身的改变之外,还对前版一些遗漏掉的知识点进行了补充。为了让读者更好地理解本书的内容并尽可能地迎合大多数人的思维方式,我们在写作过程中对整本书的结构作了调整,同时对一些表达方式作了相应的改变。
和大部分ASP.NET MVC的书籍一样,《ASP.NET MVC 4框架揭秘》利用一个单独的章节来介绍Web API,这种做法实际上给很多读者造成了一种误解,让他们觉得ASP.NET Web API仅仅是ASP.NET MVC的附属产品。实际上两者不但在运行上使用不同的消息处理管道,并且这两个管道在设计上也是截然不同的,所以本书中找不到任何关于ASP.NET Web API的内容。如果你希望深入系统地学习ASP.NET Web API,可以考虑本书的姊妹篇《ASP.NET Web API 2框架揭秘》。
这是一本实用的书吗?
可能有人觉得这本剖析ASP.NET MVC框架运行原理的书没有什么“实际”的意义,因为我们每天的日常工作就是编程,知道了ASP.NET MVC从请求接收到响应回复之间整个处理流程并不会对我们的工作造成实质性的改变,这是一种极端错误的想法。学习一种软件开发技术就像是练一门功夫,不仅要苦练攻敌招式,还得研习内功心法。编程模式是攻敌招式,框架背后的设计原理是内功心法,没有内功心法支撑的招式只能是花拳绣腿,而具有极高内功修为的高手却能“无招胜有招”。
除此之外,由于我们编写的程序最终是在ASP.NET MVC框架上运行的,程序的高效性决定了它是否能够最大限度地“迎合”框架的运行机制,所以了解ASP.NET MVC框架的运行原理有利于我们写出高质量的程序。
很多读者都问笔者为何有那么多时间和精力去深入学习多个不同的开发框架(比如WCF、ASP.NET MVC和ASP.NET Web API等),其实这和从事的工作有关。多年以来,笔者在公司所作的工作就是设计、开发和维护一套内部的开发框架,这个框架的根本目的在于让我们可以采用一种类似于流水线的项目开发方式,不仅可以提高开发效率,还能提高项目本身的质量并降低对最终开发人员的技能要求,实现的途径就是让最终的开发人员只关心具体业务功能的实现,所有非业务功能都由框架本身来完成。
为了完成这个使命,我们针对.NET平台上的开发技术作了很多扩展。为了能够精准地定位采用的扩展点,我们不得不对开发技术本身有一个深刻的认识,所以深入学习.NET平台主流开发技术是笔者的本质工作之一。为了将这些实用的扩展服务于大众,笔者将这些扩展放到了相关的书籍之中。笔者自然不会将我们做的东西直接共享出来(因为这是违法的),所以书中涉及的这些扩展都经过刻意简化,因为笔者希望的不是让读者直接使用这些扩展,而是根据其体现出来的原理来设计你们需要的扩展。
ASP.NET MVC之外的一些东西
在笔者的周围存着这样的一些人,他们以刚毕业一两年的毕业生为主。他们大都工作勤奋、聪明好学,手中经常捧着GoF的《设计模式》,总是希望在将书中的设计模式应用到具体项目之中,或者希望通过项目的实践来印证他们在书本上的设计模式,但是理论和实践之间的距离总让他们感到困惑。
. 要从真实的项目或者产品中学习“实用”的软件架构设计知识,先得确定目标项目或者产品中采用的架构思想和设计模式是正确的,而我们参与的很多项目其实被“架构”得一塌糊涂。对于像ASP.NET这样的产品,其基础架构能够在很长一段时间内保持不变,本身就证明了应用在上面的架构设计的正确性,它们不正是我们学习架构设计最好的素材吗?本书对ASP.NET MVC框架的运行机制进行了深入剖析,实际上是将ASP.NET MVC的整个设计展示在读者面前,读者也许可以将本书作为一本“架构设计”的书来读。
很多读者向笔者咨询针对一种新的开发技术,如何才能更加有效地掌握其“精髓”。这是一个关于学习方法的问题,笔者个人采用的学习方法不可能适用于所有的人。尽管如此,本书也或多或少地体现了笔者个人采用的学习方法,所以在论述某个知识点的时候,不但会告诉读者“是什么”和“为什么”,还会告诉读者“如何证明是这样”。换句话说,笔者不仅仅将某个论点抛给你,还会为你展现整个论证的过程。
本书的写作特点
和其他同类书籍作者总是从“静态编程”作为切入点不同,笔者以“动态执行”的视角来审视ASP.NET MVC框架。本书以框架本身处理请求的流程为主线,力求将ASP.NET MVC框架从接收请求到回复响应的整个流程完整而清晰地展现在读者面前。在本书的第1章中,我们设计了一个“迷你版”的ASP.NET MVC框架,其目的在于让读者能够对ASP.NET MVC的执行管道有一个整体的认识,至于组成这个管道的每个环节,则通过后续的章节对其架构设计进行详细介绍,对其执行原理进行深入剖析。
本书具有一个与其他中文原创或者翻译书籍截然不同的特点,那就是几乎所有的术语都采用英文,比如Controller、Action和Model在本书中并没有翻译成中文“控制器”、“操作”和“模型”。因为笔者认为很多术语其实很难找到一个语义完全等同的中文词组或短语与之对应,对于习惯了英文作为“开发语言”的读者来说,强行翻译其实是不必要的。
除此之外,这不是一本纯理论的书,而是一本“实证型”的书,在书中提供了一百多个可供单独下载的实例演示。这些实例在本书中具有不同的作用,有的是为了探测和证明对应的论点,有的是为了演示某种实用的编程技巧。
目录
第1章 asp.net + mvc 1
1.1 传统mvc模式 2 1.1.1 自治视图 2 1.1.2 什么是mvc模式 3 1.2 mvc的变体 4 1.2.1 mvp 5 1.2.2 model 2 13 1.2.3 asp.net mvc与model 2 15 1.3 iis/asp.net管道 15 1.3.1 iis 5.x与asp.net 16 1.3.2 iis 6.0与asp.net 17 1.3.3 iis 7.0与asp.net 19 1.3.4 asp.net集成 20 1.3.5 asp.net管道 22 1.4 asp.net mvc是如何运行的 28 1.4.1 建立在“迷你版”asp.net mvc上的web应用 28 1.4.2 路由 31 1.4.3 controller的激活 37 1.4.4 action的执行 411.4.5 完整的流程 49
第2章 路由 51 2.1 asp.net路由 52 2.1.1 请求url与物理文件的分离 52 2.1.2 实例演示:通过路由实现请求地址与.aspx页面的映射(s201) 53 2.1.3 route与routetable 57 2.1.4 路由注册 65 2.1.5 根据路由规则生成url 77 2.2 asp.net mvc路由 79 2.2.1 路由映射 79 2.2.2 路由注册(s210) 80 2.2.3 缺省url参数 83 2.2.4 基于area的路由映射 85 2.2.5 链接和url的生成 91 2.3 动态httphandler映射 98 2.3.1 urlroutingmodule 99 2.3.2 pageroutehandler与mvcroutehandler 100 2.3.3 asp.net路由系统扩展 101 2.3.4 实例演示:通过自定义route对asp.net路由系统进行扩展(s214) 102 第3章 controller的激活 107 3.1 controller激活系统全景展示 108 3.1.1 controller 108 3.1.2 controllerfactory 114 3.1.3 controllerbuilder 115 3.1.4 controller的激活与路由 122 3.2 controller默认激活机制 125 3.2.1 controller类型的解析 125 3.2.2 controller类型的缓存 130 3.2.3 controller的释放和会话状态行为的控制 131 3.3 ioc的应用 133 3.3.1 从unity来认识ioc 133 3.3.2 controller与model的解耦 135 3.3.3 基于ioc的controllerfactory 137 3.3.4 基于ioc的controlleractivator 143 3.3.5 基于ioc的dependencyresolver 145 第4章 model元数据的解析 149 4.1 model元数据 150 4.1.1 model元数据层次化结构 150 4.1.2 model元数据的定制 154 4.1.3 imetadataaware接口 171 4.2 模板化数据的呈现 176 4.2.1 实例演示:通过模板将布尔值显示为radiobutton(s409) 176 4.2.2 预定义模板 178 4.2.3 针对数据类型的模板 185 4.2.4 数据类型名称 v.s. 模板名称 189 4.2.5 模板的获取与执行 193 4.2.6 实例演示:通过定制model元数据和自定义模板 实现预定义列表的呈现(s412)197 4.3 model元数据的提供机制 205 4.3.1 再谈modelmetadata 206 4.3.2 modelmetadataprovider 210 4.3.3 model元数据提供系统的扩展 214 第5章 3个重要的描述对象 217 5.1 controllerdescriptor 218 5.1.1 reflectedcontrollerdescriptor 219 5.1.2 reflectedasynccontrollerdescriptor 228 5.2 actiondescriptor 229 5.2.1 asyncactiondescriptor 230 5.2.2 reflectedactiondescriptor 231 5.2.3 reflectedasyncactiondescriptor 232 5.2.4 taskasyncactiondescriptor 233 5.3 parameterdescriptor 234 第6章 model的绑定(一) 236 6.1 源数据的提供 237 6.1.1 namevaluecollectionvalueprovider 238 6.1.2 dictionaryvalueprovider 246 6.1.3 valueproviderfactory 254 6.1.4 valueproviderfactories 255 6.2 modelbinder及其提供策略 259 6.2.1 modelbinder 259 6.2.2 modelbinderprovider 265 6.2.3 modelbinders 268 6.2.4 custommodelbinderattribute 271 6.2.5 针对参数的modelbinder是如何创建的 274 6.3 model绑定的实施 276 6.3.1 绑定上下文的初始化 277 6.3.2 绑定过程中对modelstate的设置 279 第7章 model的绑定(二) 283 7.1 绑定简单对象 284 7.1.1 利用valueprovider绑定简单对象 284 7.1.2 实例演示:利用mydefaultmodelbinder绑定简单类型参数(s701) 286 7.2 绑定复杂对象 289 7.2.1 复杂对象层次化结构 289 7.2.2 递归式绑定 291 7.2.3 实例演示:利用mydefaultmodelbinder绑定复杂类型参数(s702、s703) 294 7.3 绑定集合 297 7.3.1 针对同名数据项的集合绑定 297 7.3.2 针对索引的集合绑定 302 7.4 绑定字典 311 7.4.1 字典是一个复杂类型的集合 311 7.4.2 针对字典类型的model绑定策略 312 7.4.3 实例演示:利用mydefaultmodelbinder绑定字典类型参数(s707) 316 第8章 model的验证(一) 318 8.1 几种参数验证方式 319 8.1.1 modelerror 319 8.1.2 验证消息的呈现 320 8.1.3 手工验证绑定的参数 322 8.1.4 使用validationattribute特性 327 8.1.5 让数据类型实现ivalidatableobject接口 330 8.1.6 让数据类型实现idataerrorinfo接口 332 8.2 modelvalidator及其提供策略 334 8.2.1 modelvalidator与modelvalidatorprovider 334 8.2.2 dataannotationsmodelvalidator 337 8.2.3 validatableobjectadapter 337 8.2.4 dataerrorinfomodelvalidator 338 8.2.5 clientmodelvalidator 339 8.2.6 compositemodelvalidator 341 8.3 model验证的实施 345 8.3.1 model绑定过程中的验证 346 8.3.2 实例演示:模拟model绑定中的验证(s810) 347 8.3.3 针对“必需”数据成员的验证 351 第9章 model的验证(二) 354 9.1 validationattribute特性 355 9.1.1 数据是如何被验证的 356 9.1.2 几个常用的validationattribute 358 9.1.3 应用validationattribute特性的唯一性 360 9.2 dataannotationsmodelvalidator及其提供策略 364 9.2.1 “适配”型dataannotationsmodelvalidator 365 9.2.2 dataannotationsmodelvalidatorprovider 368 9.2.3 将validationattribute特性应用到参数上 375 9.2.4 一种model类型,多种验证规则 382 9.3 客户端验证 389 9.3.1 jquery验证 390 9.3.2 基于jquery的model验证 394 9.3.3 自定义验证 398 第10章 action方法的执行 402 10.1 异步action的定义 403 10.1.1 基于线程池的请求处理机制 403 10.1.2 两种异步action方法的定义 404 10.1.3 asyncmanager 406 10.2 各种同步与异步组件 412 10.2.1 mvchandler 412 10.2.2 controller 413 10.2.3 actioninvoker 414 10.2.4 controllerdescriptor 420 10.2.5 actiondescriptor 423 10.3 目标方法的执行 430 10.3.1 action方法并不以“反射”方式执行 430 10.3.2 实例演示:采用针对表达式树执行action方法(s1010) 432 第11章 view的呈现 437 11.1 actionresult 438 11.1.1 emptyresult 438 11.1.2 contentresult 439 11.1.3 fileresult 446 11.1.4 javascriptresult 451 11.1.5 jsonresult 455 11.1.6 httpstatuscoderesult 457 11.1.7 redirectresult/redirecttorouteresult 458 11.2 viewresult与viewengine 461 11.2.1 view引擎中的view 461 11.2.2 viewengine 463 11.2.3 viewresult的执行 465 11.3 razor引擎 474 11.3.1 view的编译原理 475 11.3.2 webviewpage与webviewpage[tmodel] 480 11.3.3 razorview 485 11.3.4 razorviewengine 495 第12章 过滤器 499 12.1 filter及其提供机制 500 12.1.1 filter与filterprovider 500 12.1.2 以特性方式注册过滤器 502 12.1.3 controller本身就是过滤器 504 12.1.4 过滤器的全局注册 504 12.1.5 实例演示:验证filter的提供机制和执行顺序(s1201,s1202,s1203) 506 12.2 authenticationfilter 511 12.2.1 authenticationfilter的执行流程 512 12.2.2 实例演示:通过自定义authenticationfilter实现basic认证(s1204) 513 12.3 authorizationfilter 518 12.3.1 authorizeattribute 518 12.3.2 requirehttpsattribute 520 12.3.3 validateinputattribute 520 12.3.4 validateantiforgerytokenattribute 523 12.3.5 childactiononlyattribute 527 12.4 actionfilter 528 12.4.1 actionfilter的执行流程 529 12.4.2 actionfilter对actionresult的设置 530 12.4.3 异常处理 532 12.5 exceptionfilter 534 12.5.1 handleerrorattribute 535 12.5.2 实例演示:利用自定义的exceptionfilter集成enterprise library进行异常处理(s1207, s1208, s1209) 537 12.6 resultfilter与overridefilter 551 12.6.1 resultfilter的执行流程 552 12.6.2 屏蔽外围过滤器 553 第13章 特性路由 556 13.1 特性路由注册 557 13.1.1 routeinfoprovider特性 557 13.1.2 基本路由映射 558 13.1.3 让路由模板能够尽可能反映资源的层次结构 559 13.1.4 为路由变量设置约束 560 13.1.5 缺省路由变量 561 13.1.6 设置模板前缀 562 13.1.7 设置area名称 563 13.2 约束表达式的解析 564 13.2.1 rangerouteconstraint 565 13.2.2 inlineconstraintresolver 566 13.2.3 自定义约束 570 13.3 route的创建 574 13.3.1 特性路由注册的route对象 574 13.3.2 route的生成机制 579 13.3.3 controller的激活与action方法的选择 579 第14章 案例实践 581 14.1 功能简介 582 14.1.1 商品列表的呈现 582 14.1.2 订购商品 584 14.1.3 登录与错误页面 585 14.2 设计概述 586 14.2.1 controller-service-repository 586 14.2.2 ioc的应用 591 14.2.3 aop的应用 594 14.2.4 异常处理 601 14.3 编程实现 602 14.3.1 数据表的创建 603 14.3.2 repository 604 14.3.3 service 609 14.3.4 路由注册和布局 612 14.3.5 productcontroller 616 14.3.6 ordercontroller 624 14.3.7 accountcontroller 630