在ASP.NET、ASP.NET MVC和ASP.NET Web API中這些框架中都會發(fā)現(xiàn)有路由的身影,它們的原理都差不多,只不過在不同的環(huán)境下作了一些微小的修改,這也是根據(jù)每個(gè)框架的特性來制定的,今天我們就來看一看路由的結(jié)構(gòu),雖然我在MVC系列里寫過路由的篇幅不過在這里是Web API 路由對象介紹。
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),望花企業(yè)網(wǎng)站建設(shè),望花品牌網(wǎng)站建設(shè),網(wǎng)站定制,望花網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,望花網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
ASP.NET Web API開篇介紹示例
ASP.NET Web API路由對象介紹
ASP.NET Web API管道模型
ASP.NET Web API selfhost宿主環(huán)境中管道、路由
ASP.NET Web API webhost宿主環(huán)境中管道、路由
路由系統(tǒng)概念
路由的結(jié)構(gòu)
圖1
路由系統(tǒng)中最重要的部分也就是路由對象了,那我們首先就來看一下【路由對象】的定義,不管是在ASP.NET、ASP.NET MVC、還是ASP.NET Web API的路由系統(tǒng)中路由都要有個(gè)名稱,其實(shí)這個(gè)名稱并不是路由對象中的而是在注冊路由信息的時(shí)候,添加到路由對象集合的時(shí)候需要的名稱,這里也只是當(dāng)作路由的一部分,這個(gè)大家知道就好了。
在生成路由對象的時(shí)候我們要給路由賦值URL模板,這也是共同的,也是必須的,至于約束URL模板的條件是可以根據(jù)自己情況來定義的。在生成的同時(shí)框架會給路由對象賦值上【路由請求處理程序】用以作為銜接路由系統(tǒng)和框架的主體功能部分。
注冊路由到系統(tǒng)框架中
圖2
在路由定義好之后,我們便會把它注冊到系統(tǒng)框架中。
路由對象的URL匹配
圖3
在路由對象注冊到系統(tǒng)框架中之后,這個(gè)時(shí)候如果有外部的請求的到達(dá),這個(gè)時(shí)候路由系統(tǒng)會讓路由對象集合中每個(gè)路由對象對這個(gè)請求進(jìn)行匹配,就如圖4一樣。
圖4
這個(gè)時(shí)候就是路由對象所要能做出的行為就是URL的匹配,根據(jù)什么來匹配?是根據(jù)在路由對象實(shí)例化的時(shí)候定義好的URL模板和條件,拿請求信息的URL和自身定義的URL模板進(jìn)行匹配,假使沒有匹配成功則會返回Null,這個(gè)時(shí)候框架則會讓下一個(gè)路由對象來進(jìn)行匹配直到有匹配的成功為止,如果這個(gè)時(shí)候匹配成功了路由則會生成一個(gè)【路由數(shù)據(jù)對象】。
路由數(shù)據(jù)對象也很重要,因?yàn)楹罄m(xù)的框架功能部分都是使用它的,它也是整個(gè)路由系統(tǒng)的結(jié)晶,我們看下圖5
圖5
路由數(shù)據(jù)對象會保持一個(gè)生成它的路由對象的引用,然后是Values的是保存著路由對象在經(jīng)過URL匹配后的值,分別表示著URL片段的名字和對應(yīng)的URL真實(shí)值,而DataTokens則是在路由對象定義生成的時(shí)候直接帶過來的值,當(dāng)然了路由請求處理程序也是由執(zhí)行生成的路由對象帶來的。
在ASP.NET、ASP.NET MVC、ASP.NET Web API這些框架中路由系統(tǒng)都是遵循著上面的所述的這樣一個(gè)過程,只不過在不同的框架環(huán)境下使用的類型不同,做的處理也不太一樣,但是整體的流程是一致的,下面附上圖6說明了之間的類型的差異性,還有更多的細(xì)節(jié)就不一一展示了。
圖6
還有在Web API(WebHost)環(huán)境下路由顯示的是這樣實(shí)質(zhì)的本質(zhì)其實(shí)又是ASP.NET的路由系統(tǒng)在支持的,這個(gè)會在后面的Web API系列篇幅中講解。
下面簡單的演示一下在各種框架環(huán)境下的路由對象注冊,
ASP.NET:
RouteTable.Routes.MapPageRoute( "ASP.NETRoute", "ProductInfo/{action}/{id}", "~/ProductInfo.aspx", true, newRouteValueDictionary { {"id", RouteParameter.Optional }, { "action", "show" } } );
ASP.NET MVC:
RouteTable.Routes.MapRoute( "ASP.NETMVCRoute", "ProductInfo/{action}/{id}", new { controller="Product",action="show",id=RouteParameter.Optional} );
ASP.NET Web API(WEBHOST):
GlobalConfiguration.Configuration.Routes.MapHttpRoute( "WebAPIRoute", "api/{controller}/{id}", new { id=RouteParameter.Optional } );
ASP.NET Web API(SELFHOST):
HttpSelfHostConfigurationconfiguration= newHttpSelfHostConfiguration("http://loacalhost/selfhost"); using (HttpSelfHostServerselfHostServer=newHttpSelfHostServer(configuration)) { selfHostServer.Configuration.Routes.MapHttpRoute( "DefaultApi", "api/{controller}/{id}", new { id=RouteParameter.Optional}); selfHostServer.OpenAsync(); Console.Read(); }
ASP.NET Web API路由系列對象
從上圖的圖表中就可以看出,ASP.NET Web API框架在不同的宿主環(huán)境下路由系統(tǒng)中所對應(yīng)的對象類型是不同的,這里就先給大家介紹在SelfHost環(huán)境下的路由系統(tǒng)中的路由對象吧。
SelfHost宿主環(huán)境
Web API路由對象(System.Web.Http.Routing)
HttpRoute
// 摘要: // 表示自承載(即在 ASP.NET 之外承載)的路由類。 publicclassHttpRoute : IHttpRoute { publicHttpRoute(stringrouteTemplate, HttpRouteValueDictionarydefaults, HttpRouteValueDictionaryconstraints, HttpRouteValueDictionarydataTokens, HttpMessageHandlerhandler); publicIDictionaryConstraints { get; } publicIDictionary DataTokens { get; } publicIDictionary Defaults { get; } publicHttpMessageHandlerHandler { get; } publicstringRouteTemplate { get; } publicvirtualIHttpRouteDataGetRouteData(stringvirtualPathRoot, HttpRequestMessagerequest); publicvirtualIHttpVirtualPathDataGetVirtualPath(HttpRequestMessagerequest, IDictionary values); protectedvirtualboolProcessConstraint(HttpRequestMessagerequest, objectconstraint, stringparameterName, HttpRouteValueDictionaryvalues, HttpRouteDirectionrouteDirection); }
可以從上面的定義中看到HttpRoute對象就是代表著在Web API框架中的路由對象了,在HttpRoute類型定義的構(gòu)造函數(shù)中的參數(shù)分別表示著路由模板、路由模板對應(yīng)的默認(rèn)值、路由匹配條件、注冊的路由附帶的值以及最后的Http請求處理程序,這幾個(gè)參數(shù)值也分別對應(yīng)著HttpRoute類型中的幾個(gè)屬性,這個(gè)自行看一下就明白了。
Web API路由對象集合(System.Web.Http)
HttpRouteCollection
HttpRouteCollectionExtensions
我們先來看一下HttpRouteCollection類型的擴(kuò)展類型HttpRouteCollectionExtensions吧
publicstaticclassHttpRouteCollectionExtensions { publicstaticIHttpRouteMapHttpRoute(thisHttpRouteCollectionroutes, stringname, stringrouteTemplate); publicstaticIHttpRouteMapHttpRoute(thisHttpRouteCollectionroutes, stringname, stringrouteTemplate, objectdefaults); publicstaticIHttpRouteMapHttpRoute(thisHttpRouteCollectionroutes, stringname, stringrouteTemplate, objectdefaults, objectconstraints); publicstaticIHttpRouteMapHttpRoute(thisHttpRouteCollectionroutes, stringname, stringrouteTemplate, objectdefaults, objectconstraints, HttpMessageHandlerhandler); }
這里大家可以對比上面的路由注冊時(shí)的代碼,就可以知道我們在路由集合添加/注冊路由的時(shí)候是由HttpRouteCollectionExtensions類型的擴(kuò)展方法來進(jìn)行操作的,這個(gè)時(shí)候我們再看一下方法參數(shù)最多的那個(gè)MapHttpRoute()方法的實(shí)現(xiàn):
publicstaticIHttpRouteMapHttpRoute(thisHttpRouteCollectionroutes, stringname, stringrouteTemplate, objectdefaults, objectconstraints, HttpMessageHandlerhandler) { if (routes==null) { throwSystem.Web.Http.Error.ArgumentNull("routes"); } HttpRouteValueDictionarydictionary=newHttpRouteValueDictionary(defaults); HttpRouteValueDictionarydictionary2=newHttpRouteValueDictionary(constraints); IDictionarydataTokens=null; HttpMessageHandlerhandler2=handler; IHttpRouteroute=routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2); routes.Add(name, route); returnroute; }
這里大家就可以看到了,HttpRoute對象的創(chuàng)建操作和添加操作是在這擴(kuò)展方法里執(zhí)行的,現(xiàn)在我們就可以去看一下HttpRouteCollection類型的定義了,看一下如何創(chuàng)建的IHttpRoute對象:
publicclassHttpRouteCollection : ICollection, IEnumerable , IEnumerable, IDisposable { publicHttpRouteCollection(); publicHttpRouteCollection(stringvirtualPathRoot); publicvirtualintCount { get; } publicvirtualboolIsReadOnly { get; } publicvirtualstringVirtualPathRoot { get; } publicvirtualvoidAdd(stringname, IHttpRouteroute); publicIHttpRouteCreateRoute(stringrouteTemplate, objectdefaults, objectconstraints); publicIHttpRouteCreateRoute(stringrouteTemplate, IDictionary defaults, IDictionary constraints, IDictionary dataTokens); publicvirtualIHttpRouteCreateRoute(stringrouteTemplate, IDictionary defaults, IDictionary constraints, IDictionary dataTokens, HttpMessageHandlerhandler); publicvirtualIHttpRouteDataGetRouteData(HttpRequestMessagerequest); }
這里只是其中的一部分,下面我們就來看一下具體的實(shí)現(xiàn),其實(shí)就是實(shí)例化一個(gè)HttpRoute路由對象根據(jù)用戶配置的參數(shù)信息:
publicvirtualIHttpRouteCreateRoute(stringrouteTemplate, IDictionarydefaults, IDictionary constraints, IDictionary dataTokens, HttpMessageHandlerhandler) { HttpRouteValueDictionarydictionary=newHttpRouteValueDictionary(defaults); HttpRouteValueDictionarydictionary2=newHttpRouteValueDictionary(constraints); returnnewHttpRoute(routeTemplate, dictionary, dictionary2, newHttpRouteValueDictionary(dataTokens), handler); }
這是路由對象集合類型的第一個(gè)作用就是添加/注冊路由信息,那么第二個(gè)呢?就是根據(jù)請求信息來匹配路由對象,上面也說過了,其實(shí)真正根據(jù)請求來匹配的并不是路由對象集合類型(HttpRouteCollection),而是在其中的每個(gè)路由,我們看一下HttpRouteCollection的障眼法:
publicvirtualIHttpRouteDataGetRouteData(HttpRequestMessagerequest) { if (request==null) { throwSystem.Web.Http.Error.ArgumentNull("request"); } foreach (IHttpRouterouteinthis._collection) { IHttpRouteDatarouteData=route.GetRouteData(this._virtualPathRoot, request); if (routeData!=null) { returnrouteData; } } returnnull; }
從這里可以看出在路由匹配完成后會返回一個(gè)實(shí)現(xiàn)IHttpRouteDatarouteData接口的對象,也就是上面所說的路由數(shù)據(jù)對象。
Web API路由數(shù)據(jù)對象(System.Web.Http.Routing)
HttpRouteData
publicclassHttpRouteData : IHttpRouteData { publicHttpRouteData(IHttpRouteroute); publicHttpRouteData(IHttpRouteroute, HttpRouteValueDictionaryvalues); publicIHttpRouteRoute { get; } publicIDictionaryValues { get; } }
其實(shí)這里都不用講了,上面都講過了,HttpRouteData對象包含著生成它的路由對象(HttpRoute)的引用,并且Values值就是經(jīng)過匹配過后的路由模板值,key鍵對應(yīng)著Url模板的片段值,value對應(yīng)著的是片段對應(yīng)的真實(shí)值。
SelfHost環(huán)境下的路由就說到這里,大家看一下如下的示意圖,簡單的表示了在SelfHost環(huán)境下路由的一個(gè)處理過程,具體的細(xì)節(jié)會在后面的篇幅講解。
圖7
WebHost宿主環(huán)境
Web API路由對象(System.Web.Http.WebHost.Routing)
HostedHttpRoute
internalclassHostedHttpRoute : IHttpRoute { //Methods publicHostedHttpRoute(stringuriTemplate, IDictionarydefaults, IDictionary constraints, IDictionary dataTokens, HttpMessageHandlerhandler); publicIHttpRouteDataGetRouteData(stringrootVirtualPath, HttpRequestMessagerequest); publicIHttpVirtualPathDataGetVirtualPath(HttpRequestMessagerequest, IDictionary values); //Properties publicIDictionary Constraints { get; } publicIDictionary DataTokens { get; } publicIDictionary Defaults { get; } publicHttpMessageHandlerHandler { get; privateset; } internalRouteOriginalRoute { get; privateset; } publicstringRouteTemplate { get; } }
從上面的代碼定義中可以看到HostedHttpRoute是程序集內(nèi)部類型,并且是直接繼承自IHttpRoute接口,跟SelfHost環(huán)境中的HttpRoute對象是一點(diǎn)關(guān)系都沒有。
從它定義的內(nèi)部結(jié)構(gòu)來看它跟HttpRoute對象的結(jié)構(gòu)相似,還是那些屬性那些個(gè)對象,唯一不同的就是多了個(gè)OriginalRoute的只讀屬性(對于外部來說),這個(gè)屬性也就是封裝的HttpWebRoute對象,看下封裝時(shí)的實(shí)現(xiàn)
publicHostedHttpRoute(stringuriTemplate, IDictionarydefaults, IDictionary constraints, IDictionary dataTokens, HttpMessageHandlerhandler) { RouteValueDictionarydictionary= (defaults!=null) ?newRouteValueDictionary(defaults) : null; RouteValueDictionarydictionary2= (constraints!=null) ?newRouteValueDictionary(constraints) : null; RouteValueDictionarydictionary3= (dataTokens!=null) ?newRouteValueDictionary(dataTokens) : null; this.OriginalRoute=newHttpWebRoute(uriTemplate, dictionary, dictionary2, dictionary3, HttpControllerRouteHandler.Instance, this); this.Handler=handler; }
在HostedHttpRoute對象構(gòu)造函數(shù)中可以清楚的看到OriginalRoute屬性是賦值的HttpWebRoute對象的實(shí)例,我們現(xiàn)在就來看一下HttpWebRoute對象的定義:
internalclassHttpWebRoute : Route { //Fields internalconststringHttpRouteKey="httproute"; //Methods publicHttpWebRoute(stringurl, RouteValueDictionarydefaults, RouteValueDictionaryconstraints, RouteValueDictionarydataTokens, IRouteHandlerrouteHandler, IHttpRoutehttpRoute); privatestaticHttpRouteDirectionConvertRouteDirection(RouteDirectionrouteDirection); privatestaticRouteValueDictionaryGetRouteDictionaryWithoutHttpRouteKey(IDictionaryrouteValues); publicoverrideVirtualPathDataGetVirtualPath(RequestContextrequestContext, RouteValueDictionaryvalues); protectedoverrideboolProcessConstraint(HttpContextBasehttpContext, objectconstraint, stringparameterName, RouteValueDictionaryvalues, RouteDirectionrouteDirection); //Properties publicIHttpRouteHttpRoute { get; privateset; } }
從這里可以看到HttpWebRoute對象繼承自ASP.NET中的Route對象,現(xiàn)在就可以理解為HostedHttpRoute對象持有對ASP.NET中Route對象的引用,而在HostedHttpRoute的構(gòu)造函數(shù)實(shí)現(xiàn)中,對OriginalRoute屬性是賦值實(shí)例化的時(shí)候,在最后傳入了一個(gè)HttpControllerRouteHandler類型的路由處理程序,實(shí)則是給ASP.NET中的Route對象的路由處理程序(Routehandler屬性)進(jìn)行的賦值。這里路由的具體的操作后續(xù)篇幅中會有講到一個(gè)全面的過程。
Web API路由對象集合(System.Web.Http.WebHost.Routing
HostedHttpRouteCollection
internalclassHostedHttpRouteCollection : HttpRouteCollection { //Fields privatereadonlyRouteCollection_routeCollection; //Methods publicHostedHttpRouteCollection(RouteCollectionrouteCollection); publicoverridevoidAdd(stringname, IHttpRouteroute); publicoverridevoidClear(); publicoverrideboolContains(IHttpRouteitem); publicoverrideboolContainsKey(stringname); publicoverridevoidCopyTo(IHttpRoute[] array, intarrayIndex); publicoverridevoidCopyTo(KeyValuePair[] array, intarrayIndex); publicoverrideIHttpRouteCreateRoute(stringuriTemplate, IDictionary defaults, IDictionary constraints, IDictionary dataTokens, HttpMessageHandlerhandler); publicoverrideIEnumerator GetEnumerator(); publicoverrideIHttpRouteDataGetRouteData(HttpRequestMessagerequest); publicoverrideIHttpVirtualPathDataGetVirtualPath(HttpRequestMessagerequest, stringname, IDictionary values); publicoverridevoidInsert(intindex, stringname, IHttpRoutevalue); privatestaticNotSupportedExceptionNotSupportedByHostedRouteCollection(); privatestaticNotSupportedExceptionNotSupportedByRouteCollection(); publicoverrideboolRemove(stringname); publicoverrideboolTryGetValue(stringname, outIHttpRouteroute); //Properties publicoverrideintCount { get; } publicoverrideIHttpRoutethis[stringname] { get; } publicoverrideIHttpRoutethis[intindex] { get; } publicoverridestringVirtualPathRoot { get; } }
看到這里的代碼定義,HostedHttpRouteCollection對象同樣也是程序集內(nèi)部類型,繼承自ASP.NET中的RouteCollection對象,這里要說是CreateRoute()方法和GetRouteData()方法返回的分別是HostedHttpRoute對象和HostedHttpRouteData對象,其實(shí)在GetRouteData()方法中起初生成的就是Routedata對象,只不過在返回的時(shí)候經(jīng)過HostedHttpRouteData對象封裝了一下。
Web API路由數(shù)據(jù)對象(System.Web.Http.WebHost.Routing)
HostedHttpRouteData
這里我們看一下HostedHttpRouteData類型的定義:
internalclassHostedHttpRouteData : IHttpRouteData { //Methods publicHostedHttpRouteData(RouteDatarouteData); //Properties internalRouteDataOriginalRouteData { get; privateset; } publicIHttpRouteRoute { get; privateset; } publicIDictionaryValues { get; } }
從構(gòu)造函數(shù)的定義就可以看出來是HostedHttpRouteData是封裝的RouteData對象,這些路由流程細(xì)節(jié)后面篇幅中會有講解。
最后我們看一下在WebHost宿主環(huán)境下的路由示意圖。
圖8