Route对象继承自RouteBase代表一个Url模板的配置,包括Url的模板的字符串,如:api/order/102304,还有一些辅助性的内容,这不是本节的重点,我们只要知道它是用来做Url的配置即可; Route对象不是直接被我们实例化的,而是通过应用层的扩展方法进行实例化,为什么要这么做,其实这里就是路由为什么能转到上层的关键点;
根据ASP.NETMVC中的路由集合扩展类,也就是System.Web.Mvc.RouteCollectionExtensions静态类中的扩展方法,这些扩展方法就是用来包装我们在应用ASP.NET的时候配置Route使用的;是否还记得我们第4】节的一开始介绍了一个依赖注入接口的原理,这里将通过依赖注入接口达到外挂自定义实现的目的;
在Route源码中,我们将看到它有一个IRouteHander接口类型的属性RouteHander;
public class Route : RouteBase { public IRouteHandler RouteHandler { get; set; } }
这个IRouteHandler接口类型的属性就是我们ASP.NETMVC将要实现的一个IRouteHandler接口;而这个接口的定义:
public interface IRouteHandler { IHttpHandler GetHttpHandler (RequestContext requestContext); }
很简单,就是为了创建出ASP.NET管道引擎最后执行的IHttpHandler接口; Route类有一个重写了RouteBase的核心方法:
public override RouteData GetRouteData (HttpContextBase httpContext)
该方法是用来获取当前路由的一些匹配数据的,关于RouteData在4.1】节介绍过,详细我们将看下面关于对它的详细分析,这里将不做介绍了;
小结:其实Route对象还算简单,关键的两点就是GetRouteData方法和IRouteHander接口,前者是用来获取当前路由匹配成功后的路由信息,而后者是用来返回最终要执行的IHttpHandler接口;
【RouteCollection、RouteTable】
RouteCollecton和RouteTable对象比较简单;我们先来看RouteCollection对象,首先你可能会有疑问,为什么不用一个简单的Collection类型的对象来存放Route实例,非要实现了一个RouteCollection;不看源码还真不知道它内部做了很多工作,首先最重要的就是线程并发情况下的Look机制;由于我们的RouteCollection对象是全局静态对象,会同时存在着多个线程并发的读取这个对象,所以必须在对集合访问的时候进行互斥控制;比如说这段代码:
public void Add (string name, RouteBase item) { lock (GetWriteLock ()) { base.Add (item); if (!String.IsNullOrEmpty (name)) d.Add (name, item); } }
在添加路由的时候首先锁住写入对象,然后才能安全的进行操作;我们接着RouteTable对象,这个对象最简单,就是一个静态属性Routes用来存放全局路由表;
public class RouteTable { static RouteTable () { Routes = new RouteCollection (); } public static RouteCollection Routes { get; private set; } }
当首次获取Routes属性时,会在静态构造函数中实例化RouteCollection对象;
4.3】RouteValueDictionary、RouteData、RequestContext 路由数据对象模型
在第4.2】小节中,我们分析了路由系统的几个核心对象,但是核心对象要想运行起来中间必须有一些数据封装的对象为他们消除数据传递的问题;而这小节的三个核心对象真是路由系统能成功工作的必不可少的数据存放、数据传输容器的核心对象;
先基本介绍一下这几个对象的意思和彼此之间的关系:
RouteValueDictionary:路由对象内部存放中间值使用的对象,比如Url模板的默认值,命名空间,地址栏传过来的参数等等;当然也可以用来存放任何Key-Value形式的任何值;
RouteData:路由数据,用来包装根据路由Url匹配成功后的路由数据封装,最重要的是将IRouteHander接口传递到UrlRoutingModule中去;
RequestContext:请求上下文,将HttpRequest、RouteData包装起来传入IRouteHander接口获取IHttpHander接口;因为IRouteHandler接口方法GetHttpHandler需要知道当前请求的一些信息和根据当前Url处理后的路由数据才能计算出当前的IHttpHandler接口;
为了让大家对上面这些对象的解释有一个直观的认识,我们用一张图来解释他们如何关联和执行流程;
图4.3:
下面详细的分析每个对象的内部原理;
【RouteValueDictionary】
RouteValueDirctionary对象是在路由对象内部存放数据用的,比如:我们在配置路由的时候,可以指定一些默认值、命名空间等等;
看RouteValueDictionary源码定义:
public class RouteValueDictionary : IDictionary<string, object>