.NET/ASP.NETRouting路由(深入解析路由系統(tǒng)架構(gòu)原理)-創(chuàng)新互聯(lián)

閱讀目錄:

成都地區(qū)優(yōu)秀IDC服務(wù)器托管提供商(成都創(chuàng)新互聯(lián)).為客戶提供專業(yè)的資陽服務(wù)器托管,四川各地服務(wù)器托管,資陽服務(wù)器托管、多線服務(wù)器托管.托管咨詢專線:18980820575
  • 1.開篇介紹

  • 2.ASP.NET Routing 路由對象模型的位置

  • 3.ASP.NET Routing 路由對象模型的入口

  • 4.ASP.NET Routing 路由對象模型的內(nèi)部結(jié)構(gòu)

    • 4.1】UrlRoutingModule 對象內(nèi)部結(jié)構(gòu)

    • 4.2】RouteBase、Route、RouteCollection、RouteTable 路由核心對象模型

    • 4.3】RouteValueDictionary、RouteData、RequestContext 路由數(shù)據(jù)對象模型

    • 4.4】IRouteHandler 、IHttpHandler兩個接口之間的關(guān)系

  • 5.】UrlRoutingHandler 對象內(nèi)部結(jié)構(gòu)及擴(kuò)展應(yīng)用

1】開篇介紹

這篇文章讓我們愉快的學(xué)習(xí)一下ASP.NET中核心的對象模型Routing模塊,為什么說愉快呢,因為Routing正是建立在大家都比較熟悉的ASP.NET管道模型基礎(chǔ)之上的,所以相比其他一些陌生的概念會輕松很多,不過不要緊一回生二回熟;

ASP.NET Routing 系統(tǒng)是一切通過ASP.NET進(jìn)行Uri訪問應(yīng)用程序的基礎(chǔ)(并非物理文件的直接映射);隨著Routing的出現(xiàn),我們的WEB設(shè)計已經(jīng)和以前大不一樣;越來越輕量級、簡單化,都通過簡便的Uri資源的方式進(jìn)行處理,將精力放在業(yè)務(wù)的設(shè)計上;現(xiàn)在主流的Rest ful api 也都是建立在這樣的一種機(jī)制下的,然而我們的ASP.NETMVC也是一種通過獨(dú)立的Uri進(jìn)行程序訪問處理的框架,所以也是建立在ASP.NET Routing;再者就是現(xiàn)在也比較熱門的ASP.NET技術(shù)(ASP.NETWEBAPI);都是建立在Routing框架之上,可見它還是蠻重要的;

所以這篇文章讓我們來分析一下Routing的工作原理,它為什么能在不影響現(xiàn)有框架的基礎(chǔ)上提供這么好的擴(kuò)展性,真的讓人很想去一探究竟;目前非常可觀是我們都了解ASP.NET現(xiàn)有的框架知識,我們大概了解它肯定是在ASP.NET管道模型的哪個位置進(jìn)行了相應(yīng)的攔截;

下面我們帶著這個重要的線索來一點(diǎn)一點(diǎn)弄清楚它是如何為其他框架做支撐的,我最疑惑的是它是如何將WebPage和MVC進(jìn)行很好的區(qū)分的 ,最關(guān)鍵的是它如何做到只提供一個接口讓后續(xù)的相關(guān)框架都能基于這個公共的Routing接口進(jìn)行擴(kuò)展的,它的對象模型肯定很巧妙;我們需要去搞懂它,才能有信心去繼續(xù)我們的ASP.NET相關(guān)框架的后續(xù)學(xué)習(xí);

注意:全文使用Routing一詞替代ASP.NETRouting一詞,特此說明,以免概念混淆;

2】ASP.NETRouting路由對象模型的位置

問到ASP.NET最重要的擴(kuò)展點(diǎn)在哪里?我想我們都會異口同聲的說:在管道模型上,這也符合我們對此問題求解的一個基本思路;ASP.NET管道模型大家都懂的,在管道模型的相關(guān)事件中只要我們定義相關(guān)的事件就可以在管道的處理中插入自己的邏輯在里面;管道的最后執(zhí)行接口是IHttpHander類型,只有阻止原本默認(rèn)的IHttpHander接口創(chuàng)建才有可能改變整個的處理流程;

圖2.1:

.NET/ASP.NET Routing路由(深入解析路由系統(tǒng)架構(gòu)原理)

那么Routing只有在阻止IHttpHander接口的創(chuàng)建前先執(zhí)行,才能扭轉(zhuǎn)整個處理路線的機(jī)會,上圖中顯示的Application Event(2)(IHttpHander執(zhí)行)意思是說只有在IHttpHander執(zhí)行前的某個Application Event中進(jìn)行Routing的執(zhí)行才能在原本執(zhí)行IHttpHander的地方執(zhí)行其他定制的IHttpHander;而IHttpHander是ASP.NET框架的最終執(zhí)行的接口,所以如果要想改變原本執(zhí)行Page的Hander,需要提供自定義的IHttpHander接口對象;

換句話說,一切的執(zhí)行入口其實(shí)在IHttpHander.Proce***equest()方法中,但是現(xiàn)在矛盾的是ASP.NET Routing卡在中間,它讓原本直接的處理流程變的有點(diǎn)撲簌迷離,它隔開了“ASP.NET基礎(chǔ)框架 ""基于ASP.NET的應(yīng)用框架 "(如:ASP.NETMVC\ASP.NETWEBAPI\自定義框架);

注意:“ASP.NET基礎(chǔ)框架”指ASP.NET本身的框架可以理解為傳統(tǒng)的WEBFROM;而“基于ASP.NET的應(yīng)用框架”是指基于ASP.NET基礎(chǔ)框架而設(shè)計的如:MVC\WEBPAGE\WEBAPI之類的上層輕量級應(yīng)用框架;

圖2.2:

.NET/ASP.NET Routing路由(深入解析路由系統(tǒng)架構(gòu)原理)

其實(shí)這幅圖很明了的表達(dá)式了ASP.NETRouting的位置,它是用來為ASP.NETASP.NETMVC、ASP.NETWEBAPI承上啟下的關(guān)鍵紐帶;根據(jù)上面我們的分析思路,Routing是ASP.NET框架直接交互的對象模型,所以站在ASP.NET的角度它是不知道背后究竟發(fā)生了什么事情,其實(shí)ASP.NETRouting已經(jīng)在ASP.NETApplication某個生命事件中將原本的創(chuàng)建邏輯移花接木了;

3.】ASP.NETRouting路由對象模型的入口

Routing起到中間人的作用,將ASP.NET的相關(guān)邏輯透明包裝,我們雖然能在Routing的上層同樣可以使用相關(guān)的ASP.NET對象,但是概念已經(jīng)發(fā)生了根本上的變化;我們可以隨意的引入自定義的IHttpHander實(shí)現(xiàn)類,根據(jù)前端傳過來的Uri進(jìn)行策略執(zhí)行,也就是說你完全可以定義一套自己內(nèi)部使用的Uri規(guī)則和處理框架,建立在Routing基礎(chǔ)之上會很容易;

根據(jù)IHttpModule、IHttpHander的相關(guān)的知識,我們很容易就能知道從哪里可以找到Routing的入口線索,如果我們都沒有猜錯的話在系統(tǒng)的Web.config文件中肯定有一個專門處理Routing的IHttpModule,利用來它將ASP.NETRouting對象植入到ASP.NET框架之中;

我們找到.NET Framework環(huán)境配置的地方:C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config 在該文件中我們可以找到系統(tǒng)級別的配置信息;

其實(shí)這里面配置的都是系統(tǒng)級別的選項,而我們程序里面使用的Web.config文件只是用來配置跟應(yīng)用程序相關(guān)的選項,這樣的好處是我們可以在應(yīng)用程序級別很方便的改變系統(tǒng)的默認(rèn)配置;

我們找到httpModules配置節(jié),在倒數(shù)第二行發(fā)現(xiàn)一個nameUrlRoutingModule-4.0IHttpModule配置,應(yīng)該就是它了,最關(guān)鍵的是它的type信息是System.Web.Routing.UrlRoutingModule 毋庸置疑了;

現(xiàn)在就好辦多了,我們只要順藤摸瓜就能找到UrlRoutingModule是如何工作的了,不過先不能急,還有些思路并不清晰,我們繼續(xù)慢慢分析;按照這樣的一個思路,基本上我們可以斷定UrlRoutingModule就是協(xié)調(diào)ASP.NETRouting框架的紐帶;

圖3.1:

.NET/ASP.NET Routing路由(深入解析路由系統(tǒng)架構(gòu)原理)

此圖總結(jié)了我們到目前為止的一個基本思路,底層ASP.NET框架處理HTTP的對象化,然后通過ASP.NETRouting Module創(chuàng)建IHttpHandler接口對象,再然后就是執(zhí)行IHttpHander接口,共三個步驟;

作為應(yīng)用框架也就是最上層的代碼,如何才能決定ASP.NETRouting框架在處理ASP.NET的調(diào)用的時候能使用自己的IHttpHander接口對象,這個問題就需要我們深入的看一下ASP.NETRouting路由對象的內(nèi)部對象模型了;

4.】ASP.NETRouting路由對象模型的內(nèi)部結(jié)構(gòu)

這里我將使用ASP.NETMVC作為應(yīng)用框架來講解本例(目前我并不了解ASP.NETWEBAPI);那么ASP.NETMVC作為應(yīng)用層框架,是如何讓ASP.NETRouting幫助轉(zhuǎn)換IHttpHander接口的呢,這就不得不去分析Routing一些列的對象之間的組成關(guān)系及互相作用了;

根據(jù)3.】小節(jié),我們已經(jīng)了解ASP.NETRouting是使用UrlRoutingModuel對象來作為ASP.NET管道的監(jiān)聽者,然后根據(jù)一系列的內(nèi)部處理得出最終的IHttpHander接口對象;那么要想搞清楚UrlRoutingModule是如何具體的協(xié)調(diào)這一切的,必須得深入的去分析源代碼才行,盡管我們只需要了解一個80%那也少不了這個環(huán)節(jié);

注意:需要源代碼的朋友可以直接去一下站點(diǎn)獲取,微軟官方開源網(wǎng)站:http://www.codeplex.com/,開源中國:http://www.oschina.net/都可以找到源代碼;

4.1】UrlRoutingModule對象內(nèi)部結(jié)構(gòu)

首當(dāng)其沖需要搞清楚的就是UrlRoutingModule對象,根據(jù)源碼指示我們基本上能確定幾個基本的原理,首先UrlRoutingModule繼承自IHttpModule接口,訂閱了Application.PostResolveRequstCache事件,在該事件中主要是通過全局路由對象表RouteTable對象獲取提供給上層使用的依賴注入接口IRouteHander接口;

【依賴注入接口】

這里需要解釋一下什么叫依賴注入接口,可以簡單的將依賴注入接口理解成提供給外界一個具體實(shí)現(xiàn)的機(jī)會;其實(shí)就是設(shè)計原則中的“依賴倒置原則”,在RouteData的內(nèi)部不是直接依賴具體的對象;接口就是契約,提供一個接口就是約定雙方之間的契約;這里是約定了Routing框架將使用IRouteHander接口來獲取最后的處理IHttpHander接口;

下面我們將對UrlRoutingModule對象進(jìn)行分析,由于我們分析源代碼是想搞清楚對象模型之間的操作流程及關(guān)系,所以不可能分析所有的代碼,我們的重點(diǎn)是搞清楚他們的執(zhí)行順序及原理;由于UrlRoutingModule對象是導(dǎo)火線,它的出現(xiàn)將接二連三的牽連其他的對象出現(xiàn),我們將分小節(jié)進(jìn)行分析,交界處將一帶而過;

根據(jù)我們前面的分析思路,我們首先要找到UrlRoutingModule綁定Application事件的地方;

protected virtual void Init (HttpApplication application)
        {
            application.PostResolveRequestCache += PostResolveRequestCache;
        }

在PostResolverRequestCache方法中,我們將看到該方法調(diào)用了本地內(nèi)部的一個同名方法:

void PostResolveRequestCache (object o, EventArgs e)
        {
            var app = (HttpApplication) o;
            PostResolveRequestCache (new HttpContextWrapper (app.Context));
        }

然后實(shí)例化了一個HttpContextWrapper包裝對象,傳入該同名方法;

public virtual void PostResolveRequestCache (HttpContextBase context)
        {
            var rd = RouteCollection.GetRouteData (context);
           //(1)匹配RouteData對象,后面分析;
            var rc = new RequestContext (context, rd);
            //(2)封裝計算出來的RouteData對象和當(dāng)前HttpRequest對象;
            IHttpHandler http = rd.RouteHandler.GetHttpHandler (rc);
            //(3)使用(1)步驟計算出來的當(dāng)前RouteData對象中的RouteHander屬性獲取路由處理程序IHttpHander接口;
            context.Request.RequestContext = rc;
            context.RemapHandler (http);
       }

當(dāng)然我已經(jīng)省略了部分不太相關(guān)的代碼,畢竟要想說清楚所有的代碼一篇文章顯然是不夠的;上述代碼中我用紅色標(biāo)記出重要的部分;

首先是第一個重要點(diǎn)(1),匹配RouteData對象;其實(shí)就是我們在程序里面配置的Url模板數(shù)據(jù),當(dāng)請求來的時候我們需要去根據(jù)當(dāng)前請求的Url到路由表去匹配是否有符合當(dāng)前Url的路由對象;

routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

其實(shí)就是對應(yīng)著本段代碼的配置,這段代碼處理后將是一個Route對象實(shí)例,而上面的RouteCollection就很好理解了,它是Route的強(qiáng)類型集合;

到目前為止,已經(jīng)出現(xiàn)了好幾個跟Route相關(guān)的對象,沒關(guān)系,當(dāng)我們將整條線分析到頭時將很清楚他們的作用;

第二個重要點(diǎn)(2),封裝RequestContext對象,其實(shí)我們從類型的名稱上就能確定它的用途,它是請求上下文,也是有界上下文;這里面封裝了在下面獲取IHttpHander接口時將需要當(dāng)作參數(shù);

第三個重點(diǎn)(3),利用前面的匹配得到的RouteData對象,其實(shí)RouteData是路由數(shù)據(jù)的意思,那么什么叫路由數(shù)據(jù):就是路由匹配成功后所生成的和路由相關(guān)的數(shù)據(jù);還記得我們在3】節(jié)分析的原理嗎,UrlRoutingModule對上層提供基本的路由功能,但是具體的處理是在應(yīng)用層面上;

那么就是這里通過RouteData.RouteHandler.GetHttpHandler(RequestContext requestContext) 方法獲取到的最終頂層應(yīng)用處理器;

圖4.1:

.NET/ASP.NET Routing路由(深入解析路由系統(tǒng)架構(gòu)原理)

上面的解釋可以使用這幅圖來簡單的表達(dá);

UrlRoutingModule對象通過RouteData路由數(shù)據(jù)對象獲取IRouteHander接口,然后通過IRouteHander接口獲取最終的IHttpHander接口;

小結(jié):其實(shí)可以將UrlRoutingModule對象理解成是ASP.NETRouting模塊的基礎(chǔ)部分,而擴(kuò)展的地方則在我們應(yīng)用程序配置的地方,也就是我們通常在Global.asax.cs文件中配置的路由數(shù)據(jù);當(dāng)我們在配置Route對象的時候其實(shí)已經(jīng)指定了IRouteHander接口,然后這個接口會被放入RouteData同名屬性中,而不是作為零散的對象被UrlRoutingModule直接獲?。?/p>

4.2】RouteBase、Route、RouteCollection、RouteTable路由核心對象模型

在4.1 】節(jié)中,UrlRoutingModule是路由框架的基礎(chǔ)設(shè)施部分,內(nèi)置于. NETFramework系統(tǒng)及ASP.NET配置之中web.config;在ASP.NET進(jìn)行版本升級的時候該部分工作已經(jīng)由系統(tǒng)自動幫我們升級,我們在使用的時候只需要創(chuàng)建ASP.NET3.5 SP1以上的版本都會自動擁有路由系統(tǒng)功能,因為根據(jù)微軟官方MSDN介紹,路由系統(tǒng)是在ASP.NET3.5 SP1中引入的;其實(shí)我們大部分使用的ASP.NET版本已經(jīng)是4.5的,就算以前是2.0、3.0的版本也會陸續(xù)升級到最新的版本;因為新版本的框架提供了無數(shù)個讓你無法拒絕的優(yōu)勢;

那么當(dāng)基礎(chǔ)部分有了之后我們能做到就是應(yīng)用編程接口的編程,其實(shí)這部分才是我們接觸的地方;而這一小節(jié)我們將重點(diǎn)分析路由系統(tǒng)提供給我們應(yīng)用層面的編程接口,也就是上面標(biāo)題列出的幾個核心對象;

先基本介紹一下這幾個對象的意思和彼此之間的關(guān)系:

RouteBase:很明顯是Route的基類,提供了作為自定義路由對象的頂層抽象,所有的路由框架的內(nèi)部均使用抽象的RouteBase為依賴;

Route:路由系統(tǒng)默認(rèn)實(shí)現(xiàn)的路由對象繼承自RouteBase抽象基類,用來作為我們默認(rèn)的路由配置對象,當(dāng)然你可以可是實(shí)現(xiàn)自己的Route對象;

RouteCollection:Route作為單個Url的配置,那么系統(tǒng)中肯定會有多個Url規(guī)則的配置,所以RouteCollection對象是表示Route的強(qiáng)類型集合,該類繼承自 Collection<RouteBase> 類型;所以RouteCollection是用來作為Route的集合管理用的;注意這里的泛型Collection<T>中的RouteBase,再一次提醒我們要“依賴倒置”;

RouteTable:用來存放RouteCollection對象,路由表中有一系列的路由對象,而這一系列的對象就是RouteCollection管理的;在RouteTable中用Routes靜態(tài)屬性表示當(dāng)前系統(tǒng)全局的路由映射表;

這里很明顯能看出來對路由的一層一層抽象,從簡單的Route表示一個路由映射,再到表示Route的集合RouteCollection,再到最后的RouteTable的,抽象的很OO;

為了讓大家對上面這些對象的解釋有一個直觀的認(rèn)識,我們用一張圖來解釋他們?nèi)绾侮P(guān)聯(lián)和執(zhí)行流程;

圖4.2:

.NET/ASP.NET Routing路由(深入解析路由系統(tǒng)架構(gòu)原理)

下面我們將深入到各個對象的內(nèi)部去摸索一下他們之間的交互,我們根據(jù)這種引用關(guān)系來分析,首先是Route對象;

【Route、RouteBase】

Route對象繼承自RouteBase代表一個Url模板的配置,包括Url的模板的字符串,如:api/order/102304,還有一些輔助性的內(nèi)容,這不是本節(jié)的重點(diǎn),我們只要知道它是用來做Url的配置即可; Route對象不是直接被我們實(shí)例化的,而是通過應(yīng)用層的擴(kuò)展方法進(jìn)行實(shí)例化,為什么要這么做,其實(shí)這里就是路由為什么能轉(zhuǎn)到上層的關(guān)鍵點(diǎn);

根據(jù)ASP.NETMVC中的路由集合擴(kuò)展類,也就是System.Web.Mvc.RouteCollectionExtensions靜態(tài)類中的擴(kuò)展方法,這些擴(kuò)展方法就是用來包裝我們在應(yīng)用ASP.NET的時候配置Route使用的;是否還記得我們第4】節(jié)的一開始介紹了一個依賴注入接口的原理,這里將通過依賴注入接口達(dá)到外掛自定義實(shí)現(xiàn)的目的;

在Route源碼中,我們將看到它有一個IRouteHander接口類型的屬性RouteHander;

public class Route : RouteBase
{
  public IRouteHandler RouteHandler { get; set; }
}

這個IRouteHandler接口類型的屬性就是我們ASP.NETMVC將要實(shí)現(xiàn)的一個IRouteHandler接口;而這個接口的定義:

public interface IRouteHandler
{
    IHttpHandler GetHttpHandler (RequestContext requestContext);
}

很簡單,就是為了創(chuàng)建出ASP.NET管道引擎最后執(zhí)行的IHttpHandler接口; Route類有一個重寫了RouteBase的核心方法:

public override RouteData GetRouteData (HttpContextBase httpContext)

該方法是用來獲取當(dāng)前路由的一些匹配數(shù)據(jù)的,關(guān)于RouteData在4.1】節(jié)介紹過,詳細(xì)我們將看下面關(guān)于對它的詳細(xì)分析,這里將不做介紹了;

小結(jié):其實(shí)Route對象還算簡單,關(guān)鍵的兩點(diǎn)就是GetRouteData方法和IRouteHander接口,前者是用來獲取當(dāng)前路由匹配成功后的路由信息,而后者是用來返回最終要執(zhí)行的IHttpHandler接口;

【RouteCollection、RouteTable】

RouteCollecton和RouteTable對象比較簡單;我們先來看RouteCollection對象,首先你可能會有疑問,為什么不用一個簡單的Collection類型的對象來存放Route實(shí)例,非要實(shí)現(xiàn)了一個RouteCollection;不看源碼還真不知道它內(nèi)部做了很多工作,首先最重要的就是線程并發(fā)情況下的Look機(jī)制;由于我們的RouteCollection對象是全局靜態(tài)對象,會同時存在著多個線程并發(fā)的讀取這個對象,所以必須在對集合訪問的時候進(jìn)行互斥控制;比如說這段代碼:

public void Add (string name, RouteBase item)
{
    lock (GetWriteLock ()) {
        base.Add (item);
        if (!String.IsNullOrEmpty (name))
            d.Add (name, item);
    }
}

在添加路由的時候首先鎖住寫入對象,然后才能安全的進(jìn)行操作;我們接著RouteTable對象,這個對象最簡單,就是一個靜態(tài)屬性Routes用來存放全局路由表;

public class RouteTable
{
    static RouteTable ()
    {
        Routes = new RouteCollection ();
    }
    public static RouteCollection Routes { get; private set; }
}

當(dāng)首次獲取Routes屬性時,會在靜態(tài)構(gòu)造函數(shù)中實(shí)例化RouteCollection對象;

4.3】RouteValueDictionary、RouteData、RequestContext 路由數(shù)據(jù)對象模型

在第4.2】小節(jié)中,我們分析了路由系統(tǒng)的幾個核心對象,但是核心對象要想運(yùn)行起來中間必須有一些數(shù)據(jù)封裝的對象為他們消除數(shù)據(jù)傳遞的問題;而這小節(jié)的三個核心對象真是路由系統(tǒng)能成功工作的必不可少的數(shù)據(jù)存放、數(shù)據(jù)傳輸容器的核心對象;

先基本介紹一下這幾個對象的意思和彼此之間的關(guān)系:

RouteValueDictionary:路由對象內(nèi)部存放中間值使用的對象,比如Url模板的默認(rèn)值,命名空間,地址欄傳過來的參數(shù)等等;當(dāng)然也可以用來存放任何Key-Value形式的任何值;

RouteData:路由數(shù)據(jù),用來包裝根據(jù)路由Url匹配成功后的路由數(shù)據(jù)封裝,最重要的是將IRouteHander接口傳遞到UrlRoutingModule中去;

RequestContext:請求上下文,將HttpRequest、RouteData包裝起來傳入IRouteHander接口獲取IHttpHander接口;因為IRouteHandler接口方法GetHttpHandler需要知道當(dāng)前請求的一些信息和根據(jù)當(dāng)前Url處理后的路由數(shù)據(jù)才能計算出當(dāng)前的IHttpHandler接口;

為了讓大家對上面這些對象的解釋有一個直觀的認(rèn)識,我們用一張圖來解釋他們?nèi)绾侮P(guān)聯(lián)和執(zhí)行流程;

圖4.3:

.NET/ASP.NET Routing路由(深入解析路由系統(tǒng)架構(gòu)原理)

下面詳細(xì)的分析每個對象的內(nèi)部原理;

【RouteValueDictionary】

RouteValueDirctionary對象是在路由對象內(nèi)部存放數(shù)據(jù)用的,比如:我們在配置路由的時候,可以指定一些默認(rèn)值、命名空間等等;

看RouteValueDictionary源碼定義:

public class RouteValueDictionary : IDictionary<string, object>

該類型繼承自字典接口IDictionary<string,object>,繼承自字典接口而不是繼承自字典基類目的只是想使用字典的行為而不是它的默認(rèn)實(shí)現(xiàn);在RouteValueDictionary內(nèi)部使用了一個Dictionary<string,object>類型作為最終容器;

Dictionary<string,object> d = new Dictionary<string,object> (CaseInsensitiveStringComparer.Instance);

在構(gòu)造函數(shù)中使用了一個內(nèi)部類CaseInsensitiveStringComparer進(jìn)行Key的相等比較:

internal class CaseInsensitiveStringComparer : IEqualityComparer<string>
        {
            public static readonly CaseInsensitiveStringComparer Instance = new CaseInsensitiveStringComparer ();
            public int GetHashCode (string obj)
            {
                return obj.ToLower (CultureInfo.InvariantCulture).GetHashCode ();
            }
            public bool Equals (string obj1, string obj2)
            {
                return String.Equals (obj1, obj2, StringComparison.OrdinalIgnoreCase);
            }
        }

IEqualityComparer接口還是很不錯的,不過現(xiàn)在基本上不這么用了,而是直接提供了一個Lambda做為比較函數(shù);

【RouteData】

路由數(shù)據(jù)對象,它的大概意思我想大家應(yīng)該知道了,上面提到過很多次,這里就不介紹了;我們直接看一下RouteData內(nèi)部核心代碼段:

public RouteData (RouteBase route, IRouteHandler routeHandler)
{
    // arguments can be null.
    Route = route;
    RouteHandler = routeHandler;
    DataTokens = new RouteValueDictionary ();
    Values = new RouteValueDictionary ();
}
public RouteValueDictionary DataTokens { get; private set; }
public RouteBase Route { get; set; }
public IRouteHandler RouteHandler { get; set; }
public RouteValueDictionary Values { get; private set; }

通過構(gòu)造函數(shù)我們能了解到,保存了對Route對象的引用和IRouteHander接口的引用,為什么將IRouteHandler作為構(gòu)造函數(shù)參數(shù),那是因為RouteBase根本沒有對IRouteHander接口的屬性定義;IRouteHandler接口在不在RouteBase或Route中不重要,因為Route可以是自定義的,這里的強(qiáng)制性是在RouteData中,它的構(gòu)造函數(shù)必須接受IRouteHandler類型接口;

我們接著看,在構(gòu)造函數(shù)的下面兩行代碼中分別是實(shí)例化了DataTokens、Values兩個屬性,而類型是RouteValueDictionary,這也剛好和我們上面分析的對上了;RouteValueDictionary是內(nèi)部用來保存這些零散鍵值對數(shù)據(jù)容器,在Route、RouteData還有其他地方均需要用到;就是因為RouteValueDictionary的Value是Object類型,所以可以用來存放任何類型的值,比較通用;

【RequestContext 】

RequestContext在上面也已經(jīng)接觸很多次了,表示請求上下文,也就是跟當(dāng)請求相關(guān)的所有數(shù)據(jù)都封裝在里面;在后面的文章中,我們將接觸很多類似Context的對象,如:ControlContext,ViewContext之類的,都是用來控制上下文的邊界,而不是直接傳遞零散的參數(shù);

4.4】IRouteHandler 、IHttpHander兩個接口之間的關(guān)系

IRouteHandler接口是路由框架起作用的核心,只有提供了IRouteHandler實(shí)現(xiàn)才能順利的得到背后的IHttpHandler接口;ASP.NETMVC提供了MvcRouteHandler對象來實(shí)現(xiàn)IRouteHandler接口,MvcRouteHandler在內(nèi)部實(shí)例化實(shí)現(xiàn)了IHttpHandler接口的MvcHandler對象;MvcHandler然后通過RequestContext對象獲取RouteData對象,接著得到相應(yīng)的Control信息,進(jìn)行后續(xù)的執(zhí)行處理;

5.】UrlRoutingHandler 對象內(nèi)部結(jié)構(gòu)及擴(kuò)展應(yīng)用

在ASP.NETRouting路由框架中有一個很重要的IHttpHandler接口對象UrlRoutingHanlder,我想你肯定很疑惑,為什么需要這樣一個對象;其實(shí)它的存在是為了提供給我們繞過UrlRoutingModule模塊的機(jī)會;根據(jù)上面的詳細(xì)的分析,我們知道路由的入口在UrlRoutingModule,所有的路由相關(guān)的映射工作都在該類中完成,但是有時候我們很想繞過UrlRoutingModule進(jìn)行簡單的處理或者性能方面的優(yōu)化考慮,這就派上用場了;我能想到的使用場景目前來看是對ASP.NET第版本的項目做Url重寫是比較方便,首先我們的項目需要建立在低版本的ASP.NET之上,但是需要添加Url.ReWriter的功能,就需要我們自己去實(shí)現(xiàn)這樣的功能;

但是工作量和性能都很難控制好,如果使用這里提供的UrlRoutingHandler進(jìn)行實(shí)現(xiàn)就很方便了,UrlRoutingHandler給我們使用ASP.NETRouting框架的機(jī)會同時也不需要關(guān)心是否配置了UrlRoutingModule;

public abstract class UrlRoutingHandler : IHttpHandler

根據(jù)代碼看出它是一個抽象類,直接實(shí)現(xiàn)IHttpHanlder接口,但是重要的是Proce***equest方法;

protected virtual void Proce***equest (HttpContextBase httpContext)
        {
            if (httpContext == null)
                throw new ArgumentNullException ("httpContext");
            var rd = RouteCollection.GetRouteData (httpContext);
            if (rd == null)
                throw new HttpException ("The incoming request does not match any route");
            if (rd.RouteHandler == null)
                throw new InvalidOperationException ("No  IRouteHandler is assigned to the selected route");
            RequestContext rc = new RequestContext (httpContext, rd);
            var hh = rd.RouteHandler.GetHttpHandler (rc);
            VerifyAndProce***equest (hh, httpContext);
        }
        protected abstract void VerifyAndProce***equest (IHttpHandler httpHandler, HttpContextBase httpContext);

該方法的邏輯跟UrlRoutingModule里的PostResolveRequestCache方法是差不多的,都會通過全局RouteCollection集合進(jìn)行匹配當(dāng)前的RouteData對象;那就足夠說明這個過程不會再通過UrlRoutingModule模塊;方法的最后一行是執(zhí)行一個模板方法:VerifyAndProce***equest ,該方法是留給子類去實(shí)現(xiàn)的;

那么這里將路由和執(zhí)行合在一起了,基類負(fù)責(zé)路由子類負(fù)責(zé)執(zhí)行,很不錯的設(shè)計方法;

總結(jié):這篇文章基本上介紹了跟路由相關(guān)的核心對象,但是還有一些其他輔助的類這里并沒有進(jìn)行講解,當(dāng)然如果你有興趣可以自己去看看;這篇文章是為了讓我們能對路由的處理流程及結(jié)構(gòu)有個了解,做到能在適當(dāng)?shù)臅r候進(jìn)行擴(kuò)展和查找問題;

作者:王清培

出處:http://wangqingpei557.blog.51cto.com/

本文版權(quán)歸作者和51CTO共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

當(dāng)前文章:.NET/ASP.NETRouting路由(深入解析路由系統(tǒng)架構(gòu)原理)-創(chuàng)新互聯(lián)
當(dāng)前網(wǎng)址:http://muchs.cn/article38/dpiipp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、網(wǎng)站制作、網(wǎng)站維護(hù)、云服務(wù)器、網(wǎng)站設(shè)計公司、自適應(yīng)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設(shè)計公司