ASP.NET MVC 的路由其实是创建在 ASP.NET 的路由系统之上的.
RouteTable 是一个全局路由表, 它的 Routes 静态属性是一个 RouteCollection 类型的实例,而 RouteCollection 是一个继承自 Collection<RouteBase> 的子类, RouteBase 是 ASP.NET 路由系统定义的基类html
.api
RouteBase 有一个惟一的实现类:ide
当咱们经过以下方法注册一个路由时:函数
实际是向全局路由表中添加了一个 Route 类型的实例,部分源码以下: this
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) { ...... Route route = new Route(url, (IRouteHandler) new MvcRouteHandler()) { ...... }; ...... routes.Add(name, (RouteBase) route); return route; }
从源码中咱们能够看到,添加 Route 对象的时候,直接传入了一个 MvcRouteHandler 类型的实例.url
咱们知道, ASP.NET 的路由系统对路由的解析是经过一个注册的 HttpModule 对象实现对请求的拦截,而后为当前 Http 上下文动态映射一个 HttpHandler 对象, 而这个 HttpHandler 对象会接管对当前请求的处理并最终对请求予以响应.spa
这个注册的 HttpModule 对象的类型叫作 UrlRoutingModule .3d
咱们能够在ASP.NET 的全局系统配置文件中找到它:code
<httpModules> ...... <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule"/> ...... </httpModules>
该类型在 PostResolveRequestCache 事件实现对请求的拦截:orm
在拦截时,它作了这么几件事(部分源码省略):
public virtual void PostResolveRequestCache(HttpContextBase context) { RouteData routeData = this.RouteCollection.GetRouteData(context); IRouteHandler routeHandler = routeData.RouteHandler; IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); context.RemapHandler(httpHandler); }
1.遍历全部注册的路由,也就是全部添加到全局路由表中的 Route 类型的实例,经过调用它们的 GetRouteData 方法,拿到第一个匹配的 RouteData (路由数据);
2.拿到路由数据中的 RouteHandler 对象, 其实就是 MvcRouteHandler 类型的实例;
3.调用 MvcRouteHandler 的 GetHttpHandler 方法,拿到 HttpHandler.
MvcRouteHandler 的 GetHttpHandler 方法源码以下:
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext)); return (IHttpHandler) new MvcHandler(requestContext); }
能够看到,直接 new 了一个 MvcHandler 类型的实例,
最终,请求转交给这个 MvcHandler 类型的实例处理.
ASP.NET Web API 是怎么与 ASP.NET 路由系统接轨的呢?
咱们知道, ASP.NET 的路由系统对路由的解析是经过一个注册的 HttpModule 对象实现对请求的拦截,而后为当前 Http 上下文动态映射一个 HttpHandler 对象, 而这个 HttpHandler 对象会接管对当前请求的处理并最终对请求予以响应.
这一条不只对 MVC 适用, 对 Web API 一样适用,由于他俩都是借助于 ASP.NET 的路由系统.
区别在于 HttpHandler 的类型不同而已.
ASP.NET Web API 注册路由的代码一般是这样的:
config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
config.Routes 是一个 HttpRouteCollection 类型的实例,而且是只读的.
只读的,就意味着只能在该实例所属的类的构造函数中初始化.
咱们知道,这个 config 是 HttpConfiguration 类型,它在 GlobalConfiguration 类中初始化.
在它的初始化代码中,咱们能够看到:
private static Lazy<HttpConfiguration> CreateConfiguration() { return new Lazy<HttpConfiguration>(() => { HttpConfiguration config = new HttpConfiguration(new HostedHttpRouteCollection(RouteTable.Routes)); ......return config; }); }
HttpConfiguration 实际是对 HostedHttpRouteCollection 的封装,然后者是对 RouteTable.Route 的封装. 即 ASP.NET 全局路由表的封装.
因此说, HttpConfiguration 类型封装了 ASP.NET 的全局路由表. 它的 Routes 属性的实际类型是 HostedHttpRouteCollection
咱们再回头看 config.Routes.MapHttpRoute 方法 , 也就是 HostedHttpRouteCollection 类型的 MapHttpRoute 方法:
public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler) { ...... IHttpRoute route = routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: null, handler: handler); routes.Add(name, route); return route; }
很简单,建立了一个路由,而后添加它.
咱们继续查看 HostedHttpRouteCollection 类型的 CreateRoute 方法:
public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler) { ......
return (IHttpRoute) new HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler); }
返回了一个 HostedHttpRoute 类型的实例.
咱们能够把这个方法 和 上面 MVC 的 MapRoute 方法作比较:
MVC:
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) { ...... Route route = new Route(url, (IRouteHandler) new MvcRouteHandler()) { ...... }; ...... routes.Add(name, (RouteBase) route); return route; }
是否是很是像!不一样的只是 MVC new 的路由对象是 Route 类型,而 Web API new 的路由对象是 HostedHttpRoute 类型.
讲到这里,其实 ASP.NET Web API 的路由系统尚未和 ASP.NET 的路由系统衔接起来,它们两者的关系仅仅体如今下面这句话:
HttpConfiguration 实际是对 HostedHttpRouteCollection 的封装,然后者是对 RouteTable.Route 的封装. 即 ASP.NET 全局路由表的封装.
可是,当 HostedHttpRoute 建立后,调用 HostedHttpRouteCollection 的 Add 方法添加时,衔接就真正开始了:
public override void Add(string name, IHttpRoute route) { _routeCollection.Add(name, route.ToRoute()); }
_routeCollection 是 RouteCollection 类型,没看错,就是 ASP.NET 路由系统的 RouteCollection .
因此,这句代码实际是向 ASP.NET 路由系统的路由集合中添加路由,目的就是为了让 UrlRoutingModule 可以拦截到匹配了 Web API 注册的路由的请求.
可是,问题来了,从上面 MVC 的讲解中咱们知道, ASP.NET 路由系统的 RouteCollection 是一个继承自 Collection<RouteBase> 的子类, RouteBase 是 ASP.NET 路由的基类,
而 HostedHttpRoute 是实现了 IHttpRoute 接口的实例,
IHttpRoute 和 RouteBase 风马牛不相接啊!
因此,添加时,Web API 经过 HostedHttpRoute 的 ToRoute 方法,将本身转成了 RouteBase 类型!!
这个转化很是简单:
public static Route ToRoute(this IHttpRoute httpRoute) {
...... HostedHttpRoute hostedHttpRoute = httpRoute as HostedHttpRoute; if (hostedHttpRoute != null) { return hostedHttpRoute.OriginalRoute; }
...... }
问题又来了, HostedHttpRoute 类型的 OriginalRoute 是个什么鬼?固然,确定是个 Route 类型,也就是说,它是一个 ASP.NET 路由系统定义的 Route 类型.那它是怎么来的呢?
咱们知道,在 Web API 注册路由时, MapHttpRoute 内部建立了一个 HostedHttpRoute 类型的实例,而且是直接 new 的.
那么咱们去看看 HostedHttpRoute 的构造函数:
public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler) { ...... OriginalRoute = new HttpWebRoute(uriTemplate, routeDefaults, routeConstraints, routeDataTokens, HttpControllerRouteHandler.Instance, this); ...... }
OriginalRoute 原来是一个 HttpWebRoute 类型,而 HttpWebRoute 则是 ASP.NET 路由系统定义的 Route 类型的子类.
而且,建立 HttpWebRoute 类型的实例时,传入了一个 ASP.NET 路由系统定义的 IRouteHandler 类型的实例 : HttpControllerRouteHandler.Instance
而 HttpControllerRouteHandler 的 GetHttpHandler 方法以下:
/// <summary>
/// Provides the object that processes the request.
/// </summary>
/// <param name="requestContext">An object that encapsulates information about the request.</param>
/// <returns>
/// An object that processes the request.
/// </returns>
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { return new HttpControllerHandler(requestContext.RouteData); }
返回了一个 HttpControllerHandler 类型的实例.
HttpControllerHandler 类型的XML注释则很是清晰的解释了它的做用:
/// 用于将 ASP.NET 请求传递给管道并写回结果。</summary>
这里说的管道,天然就是 Web API 的消息处理管道了.
总结:
ASP.NET MVC 和 ASP.NET Web API 都是经过 UrlRoutingModule ,在 PostResolveRequestCache 事件实现对请求的拦截.
拦截后,经过对HTTP上下文,路由等一系列处理后,
MVC 建立了 MvcHandler 进行具体的请求处理及响应;
Web API 建立了 HttpControllerHandler 进行具体的请求处理及响应.
原文出处:https://www.cnblogs.com/refuge/p/10505565.html