1】开篇介绍
这篇文章让我们愉快的学习一下ASP.NET中核心的对象模型Routing模块,为什么说愉快呢,因为Routing正是建立在大家都比较熟悉的ASP.NET管道模型基础之上的,所以相比其他一些陌生的概念会轻松很多,不过不要紧一回生二回熟;
ASP.NET Routing 系统是一切通过ASP.NET进行Uri访问应用程序的基础(并非物理文件的直接映射);随着Routing的出现,我们的WEB设计已经和以前大不一样;越来越轻量级、简单化,都通过简便的Uri资源的方式进行处理,将精力放在业务的设计上;现在主流的Rest ful api 也都是建立在这样的一种机制下的,然而我们的ASP.NETMVC也是一种通过独立的Uri进行程序访问处理的框架,所以也是建立在ASP.NET Routing;再者就是现在也比较热门的ASP.NET技术(ASP.NETWEBAPI);都是建立在Routing框架之上,可见它还是蛮重要的;
所以这篇文章让我们来分析一下Routing的工作原理,它为什么能在不影响现有框架的基础上提供这么好的扩展性,真的让人很想去一探究竟;目前非常可观是我们都了解ASP.NET现有的框架知识,我们大概了解它肯定是在ASP.NET管道模型的哪个位置进行了相应的拦截;
下面我们带着这个重要的线索来一点一点弄清楚它是如何为其他框架做支撑的,我最疑惑的是它是如何将WebPage和MVC进行很好的区分的 ,最关键的是它如何做到只提供一个接口让后续的相关框架都能基于这个公共的Routing接口进行扩展的,它的对象模型肯定很巧妙;我们需要去搞懂它,才能有信心去继续我们的ASP.NET相关框架的后续学习;
注意:全文使用Routing一词替代ASP.NETRouting一词,特此说明,以免概念混淆;
问到ASP.NET最重要的扩展点在哪里?我想我们都会异口同声的说:在管道模型上,这也符合我们对此问题求解的一个基本思路;ASP.NET管道模型大家都懂的,在管道模型的相关事件中只要我们定义相关的事件就可以在管道的处理中插入自己的逻辑在里面;管道的最后执行接口是IHttpHander类型,只有阻止原本默认的IHttpHander接口创建才有可能改变整个的处理流程;
图2.1:
那么Routing只有在阻止IHttpHander接口的创建前先执行,才能扭转整个处理路线的机会,上图中显示的Application Event(2)(IHttpHander执行)意思是说只有在IHttpHander执行前的某个Application Event中进行Routing的执行才能在原本执行IHttpHander的地方执行其他定制的IHttpHander;而IHttpHander是ASP.NET框架的最终执行的接口,所以如果要想改变原本执行Page的Hander,需要提供自定义的IHttpHander接口对象;
换句话说,一切的执行入口其实在IHttpHander.ProcessRequest()方法中,但是现在矛盾的是ASP.NET Routing 卡在中间,它让原本直接的处理流程变的有点扑簌迷离,它隔开了“ASP.NET基础框架 " 与 "基于ASP.NET的应用框架 "(如:ASP.NETMVC\\ASP.NETWEBAPI\\自定义框架);
注意:“ASP.NET基础框架”指ASP.NET本身的框架可以理解为传统的WEBFROM;而“基于ASP.NET的应用框架”是指基于ASP.NET基础框架而设计的如:MVC\\WEBPAGE\\WEBAPI之类的上层轻量级应用框架;
图2.2:
其实这幅图很明了的表达式了ASP.NETRouting的位置,它是用来为ASP.NET与ASP.NETMVC、ASP.NETWEBAPI承上启下的关键纽带;根据上面我们的分析思路,Routing是ASP.NET框架直接交互的对象模型,所以站在ASP.NET的角度它是不知道背后究竟发生了什么事情,其实ASP.NETRouting已经在ASP.NETApplication某个生命事件中将原本的创建逻辑移花接木了;
Routing起到中间人的作用,将ASP.NET的相关逻辑透明包装,我们虽然能在Routing的上层同样可以使用相关的ASP.NET对象,但是概念已经发生了根本上的变化;我们可以随意的引入自定义的IHttpHander实现类,根据前端传过来的Uri进行策略执行,也就是说你完全可以定义一套自己内部使用的Uri规则和处理框架,建立在Routing基础之上会很容易;
根据IHttpModule、IHttpHander 的相关的知识,我们很容易就能知道从哪里可以找到Routing的入口线索,如果我们都没有猜错的话在系统的Web.config文件中肯定有一个专门处理Routing的IHttpModule,利用来它将ASP.NETRouting对象植入到ASP.NET框架之中;
我们找到.NET Framework环境配置的地方:C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\Config 在该文件中我们可以找到系统级别的配置信息;
其实这里面配置的都是系统级别的选项,而我们程序里面使用的Web.config文件只是用来配置跟应用程序相关的选项,这样的好处是我们可以在应用程序级别很方便的改变系统的默认配置;
我们找到httpModules配置节,在倒数第二行发现一个name为UrlRoutingModule-4.0的IHttpModule配置,应该就是它了,最关键的是它的type信息是System.Web.Routing.UrlRoutingModule 毋庸置疑了;
现在就好办多了,我们只要顺藤摸瓜就能找到UrlRoutingModule是如何工作的了,不过先不能急,还有些思路并不清晰,我们继续慢慢分析;按照这样的一个思路,基本上我们可以断定UrlRoutingModule就是协调ASP.NETRouting框架的纽带;
图3.1:
此图总结了我们到目前为止的一个基本思路,底层ASP.NET框架处理HTTP的对象化,然后通过ASP.NETRouting Module创建IHttpHandler接口对象,再然后就是执行IHttpHander接口,共三个步骤;
作为应用框架也就是最上层的代码,如何才能决定ASP.NETRouting框架在处理ASP.NET的调用的时候能使用自己的IHttpHander接口对象,这个问题就需要我们深入的看一下ASP.NETRouting路由对象的内部对象模型了;
这里我将使用ASP.NETMVC作为应用框架来讲解本例(目前我并不了解ASP.NETWEBAPI);那么ASP.NETMVC作为应用层框架,是如何让ASP.NETRouting帮助转换IHttpHander接口的呢,这就不得不去分析Routing一些列的对象之间的组成关系及互相作用了;
根据3.】小节,我们已经了解ASP.NETRouting是使用UrlRoutingModuel对象来作为ASP.NET管道的监听者,然后根据一系列的内部处理得出最终的IHttpHander接口对象;那么要想搞清楚UrlRoutingModule是如何具体的协调这一切的,必须得深入的去分析源代码才行,尽管我们只需要了解一个80%那也少不了这个环节;
注意:需要源代码的朋友可以直接去一下站点获取,微软官方开源网站:http://www.codeplex.com/,开源中国:http://www.oschina.net/都可以找到源代码;
4.1】UrlRoutingModule对象内部结构
首当其冲需要搞清楚的就是UrlRoutingModule对象,根据源码指示我们基本上能确定几个基本的原理,首先UrlRoutingModule继承自IHttpModule接口,订阅了Application.PostResolveRequstCache事件,在该事件中主要是通过全局路由对象表RouteTable对象获取提供给上层使用的依赖注入接口IRouteHander接口;
【依赖注入接口】
这里需要解释一下什么叫依赖注入接口,可以简单的将依赖注入接口理解成提供给外界一个具体实现的机会;其实就是设计原则中的“依赖倒置原则”,在RouteData的内部不是直接依赖具体的对象;接口就是契约,提供一个接口就是约定双方之间的契约;这里是约定了Routing框架将使用IRouteHander接口来获取最后的处理IHttpHander接口;
下面我们将对UrlRoutingModule对象进行分析,由于我们分析源代码是想搞清楚对象模型之间的操作流程及关系,所以不可能分析所有的代码,我们的重点是搞清楚他们的执行顺序及原理;由于UrlRoutingModule对象是导火线,它的出现将接二连三的牵连其他的对象出现,我们将分小节进行分析,交界处将一带而过;
根据我们前面的分析思路,我们首先要找到UrlRoutingModule绑定Application事件的地方;