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