溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

.NET/ASP.NET中Routing路由的示例分析

發(fā)布時(shí)間:2021-09-03 13:32:18 來(lái)源:億速云 閱讀:163 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹了.NET/ASP.NET中Routing路由的示例分析,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

1】開(kāi)篇介紹

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

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

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

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

2】ASP.NETRouting路由對(duì)象模型的位置

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

圖2.1:

.NET/ASP.NET中Routing路由的示例分析

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

換句話說(shuō),一切的執(zhí)行入口其實(shí)在IHttpHander.ProcessRequest()方法中,但是現(xiàn)在矛盾的是ASP.NET Routing 卡在中間,它讓原本直接的處理流程變的有點(diǎn)撲簌迷離,它隔開(kāi)了“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è)計(jì)的如:MVC\WEBPAGE\WEBAPI之類(lèi)的上層輕量級(jí)應(yīng)用框架;

圖2.2:

.NET/ASP.NET中Routing路由的示例分析

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

3.】ASP.NETRouting路由對(duì)象模型的入口

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

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

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

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

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

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

圖3.1:

.NET/ASP.NET中Routing路由的示例分析

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

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

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

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

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

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

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

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

【依賴(lài)注入接口】

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

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

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

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

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

void PostResolveRequestCache (object o, EventArgs e)

    {

      var app = (HttpApplication) o;

      PostResolveRequestCache (new HttpContextWrapper (app.Context));

    }

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

public virtual void PostResolveRequestCache (HttpContextBase context)

    { 

      var rd = RouteCollection.GetRouteData (context); 

      //(1)匹配RouteData對(duì)象,后面分析; 

      var rc = new RequestContext (context, rd); 

      //(2)封裝計(jì)算出來(lái)的RouteData對(duì)象和當(dāng)前HttpRequest對(duì)象; 

      IHttpHandler http = rd.RouteHandler.GetHttpHandler (rc);

      //(3)使用(1)步驟計(jì)算出來(lái)的當(dāng)前RouteData對(duì)象中的RouteHander屬性獲取路由處理程序IHttpHander接口

      context.Request.RequestContext = rc;

      context.RemapHandler (http);

    }

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

首先是第一個(gè)重要點(diǎn)(1),匹配RouteData對(duì)象;其實(shí)就是我們?cè)诔绦蚶锩媾渲玫腢rl模板數(shù)據(jù),當(dāng)請(qǐng)求來(lái)的時(shí)候我們需要去根據(jù)當(dāng)前請(qǐng)求的Url到路由表去匹配是否有符合當(dāng)前Url的路由對(duì)象;

routes.MapRoute(

        name: "Default",

        url: "{controller}/{action}/{id}",

        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

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

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

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

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

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

圖4.1:

.NET/ASP.NET中Routing路由的示例分析

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

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

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

4.2】RouteBase、Route、RouteCollection、RouteTable路由核心對(duì)象模型

在4.1 】節(jié)中,UrlRoutingModule是路由框架的基礎(chǔ)設(shè)施部分,內(nèi)置于. NETFramework系統(tǒng)及ASP.NET配置之中web.config;在ASP.NET進(jìn)行版本升級(jí)的時(shí)候該部分工作已經(jīng)由系統(tǒng)自動(dòng)幫我們升級(jí),我們?cè)谑褂玫臅r(shí)候只需要?jiǎng)?chuàng)建ASP.NET3.5 SP1以上的版本都會(huì)自動(dòng)擁有路由系統(tǒng)功能,因?yàn)楦鶕?jù)微軟官方MSDN介紹,路由系統(tǒng)是在ASP.NET3.5 SP1中引入的;其實(shí)我們大部分使用的ASP.NET版本已經(jīng)是4.5的,就算以前是2.0、3.0的版本也會(huì)陸續(xù)升級(jí)到最新的版本;因?yàn)樾掳姹镜目蚣芴峁┝藷o(wú)數(shù)個(gè)讓你無(wú)法拒絕的優(yōu)勢(shì);

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

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

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

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

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

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

這里很明顯能看出來(lái)對(duì)路由的一層一層抽象,從簡(jiǎn)單的Route表示一個(gè)路由映射,再到表示Route的集合RouteCollection,再到最后的RouteTable的,抽象的很OO;

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

圖4.2:

.NET/ASP.NET中Routing路由的示例分析

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

【Route、RouteBase】

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

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

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

public class Route : RouteBase

{

 public IRouteHandler RouteHandler { get; set; } 

}

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

public interface IRouteHandler

{

  IHttpHandler GetHttpHandler (RequestContext requestContext);

}

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

public override RouteData GetRouteData (HttpContextBase httpContext)

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

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

【RouteCollection、RouteTable】

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

public void Add (string name, RouteBase item)

{

  lock (GetWriteLock ()) {

    base.Add (item);

    if (!String.IsNullOrEmpty (name))

      d.Add (name, item);

  }

}

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

public class RouteTable

{

  static RouteTable ()

  {

    Routes = new RouteCollection ();

  } 

  public static RouteCollection Routes { get; private set; }

}

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

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

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

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

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

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

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

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

圖4.3:

.NET/ASP.NET中Routing路由的示例分析

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

【RouteValueDictionary】

RouteValueDirctionary對(duì)象是在路由對(duì)象內(nèi)部存放數(shù)據(jù)用的,比如:我們?cè)谂渲寐酚傻臅r(shí)候,可以指定一些默認(rèn)值、命名空間等等;

看RouteValueDictionary源碼定義:

public class RouteValueDictionary : IDictionary<string, object>

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

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

在構(gòu)造函數(shù)中使用了一個(gè)內(nèi)部類(lè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接口還是很不錯(cuò)的,不過(guò)現(xiàn)在基本上不這么用了,而是直接提供了一個(gè)Lambda做為比較函數(shù);

【RouteData】

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

public RouteData (RouteBase route, IRouteHandler routeHandler)

{

  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; }

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

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

【RequestContext 】

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

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

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

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

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

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

public abstract class UrlRoutingHandler : IHttpHandler

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

protected virtual void ProcessRequest (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);

      VerifyAndProcessRequest (hh, httpContext);

    } 

 

    protected abstract void VerifyAndProcessRequest (IHttpHandler httpHandler, HttpContextBase httpContext);

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

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

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“.NET/ASP.NET中Routing路由的示例分析”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI