日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

ASP.NET Web API路由系統(tǒng):路由系統(tǒng)的幾個(gè)核心類型

 昵稱10504424 2013-08-07

雖然ASP.NET Web API框架采用與ASP.NET MVC框架類似的管道式設(shè)計(jì),但是ASP.NET Web API管道的核心部分(定義在程序集System.Web.Http.dll中)已經(jīng)移除了對(duì)System.Web.dll程序集的依賴,實(shí)現(xiàn)在ASP.NET Web API框架中的URL路由系統(tǒng)亦是如此。也就是說,ASP.NET Web API核心框架的URL路由系統(tǒng)與ASP.NET本身的路由系統(tǒng)是相對(duì)獨(dú)立的。但是當(dāng)我們采用基于Web Host的方式(定義在程序集System.Web.Http.WebHost.dll)將ASP.NET Web API承載于一個(gè)ASP.NET Web應(yīng)用的時(shí)候,真正實(shí)現(xiàn)URL路由的依然是ASP.NET本身的路由系統(tǒng),Web Host實(shí)際上在這種情況下起到了一個(gè)“適配”的作用,是兩個(gè)相對(duì)獨(dú)立的路由系統(tǒng)的“適配器”。我們先來討論一下實(shí)現(xiàn)在ASP.NET Web API框架中這個(gè)獨(dú)立的路由系統(tǒng)是如何設(shè)計(jì)的。[本文已經(jīng)同步到《How ASP.NET Web API Works?》]

目錄
一、HttpRequestMessage與HttpResponseMessage
二、HttpRouteData
三、HttpVirtualPathData
四、HttpRouteConstraint
五、HttpRoute
六、HttpRouteCollection
七、注冊(cè)路由映射
八、缺省路由變量

一、HttpRequestMessage與HttpResponseMessage

ASP.NET Web API框架通過具有如下定義的類型HttpRequestMessage表示某個(gè)HTTP請(qǐng)求的封裝。HttpRequestMessage的屬性Method和RequestUri分別表示請(qǐng)求采用的HTTP方法和請(qǐng)求地址,它們可以在相應(yīng)的構(gòu)造函數(shù)中直接被初始化,而默認(rèn)采用的HTTP方法為HTTP-GET。

   1: public class HttpRequestMessage : IDisposable
   2: {
   3:     public HttpRequestMessage();
   4:     public HttpRequestMessage(HttpMethod method, string requestUri);
   5:     public HttpRequestMessage(HttpMethod method, Uri requestUri);
   6:  
   7:     public HttpMethod                     Method { get; set; }
   8:     public Uri                            RequestUri { get; set; }
   9:     public HttpRequestHeaders             Headers { get; }
  10:     public IDictionary<string, object>    Properties { get; }    
  11:     public Version                        Version { get; set; }
  12:     public HttpContent                    Content { get; set; }
  13:  
  14:     public void Dispose();
  15: }

只讀屬性Headers表示的System.Net.Http.Headers.HttpRequestHeaders對(duì)象具有一個(gè)類似于字典的數(shù)據(jù)結(jié)構(gòu),用于存放HTTP請(qǐng)求報(bào)頭。通過利用字典類型的只讀屬性Properties,我們可以將任意屬性附加到一個(gè)HttpRequestMessage對(duì)象上。類型為System.Version的Version屬性表示請(qǐng)求的HTTP版本,默認(rèn)采用的HTTP版本為HTTP 1.1(HttpVersion.Version11)。

HttpRequestMessage具有一個(gè)Content屬性封裝了HTTP消息主體相關(guān)的信息,其類型為HttpContent。如下面的代碼片斷所示,HttpContent是一個(gè)抽象類,它定義了CopyToAsync和ReadAsByteArrayAsync兩組方法進(jìn)行主體內(nèi)容的讀寫操作。HttpContent的Headers屬性返回一個(gè)System.Net.Http.Headers.HttpContentHeaders對(duì)象代表HTTP消息主體內(nèi)容相關(guān)的報(bào)頭列表,比如表示主題內(nèi)容編碼和長度的“Content-Encoding”和“Content-Length”等。

   1: public abstract class HttpContent : IDisposable
   2: {
   3:     //其他成員
   4:     public Task<byte[]> ReadAsByteArrayAsync();
   5:     public Task<Stream> ReadAsStreamAsync();
   6:     public Task<string> ReadAsStringAsync();
   7:  
   8:     public Task CopyToAsync(Stream stream);
   9:     public Task CopyToAsync(Stream stream, TransportContext context);    
  10:  
  11:     public HttpContentHeaders Headers { get; }
  12: }

HTTP響應(yīng)的基本信息本封裝到具有如下定義的HttpResponseMessage類型中。它的RequestMessage表示與之匹配的請(qǐng)求。屬性StatusCode和表示響應(yīng)狀態(tài)碼以及輔助表示響應(yīng)狀態(tài)的文字。布爾類型的屬性IsSuccessStatusCode用于判斷是否屬性一個(gè)成功的響應(yīng),所謂“成功的響應(yīng)”指的是狀態(tài)碼在范圍[200,299]以內(nèi)的響應(yīng)。類型為HttpResponseHeaders的屬性Headers表示回復(fù)消息的HTTP報(bào)頭列表,而Version代表HTTP消息的版本,默認(rèn)采用的HTTP版本依然是HTTP 1.1(HttpVersion.Version11)。響應(yīng)消息主體內(nèi)容的讀取和寫入,以及相關(guān)內(nèi)容報(bào)頭的獲取可以通過屬性Content表示的HttpContent來完成。

   1: public class HttpResponseMessage : IDisposable
   2: {
   3:     //其他成員
   4:     public HttpRequestMessage RequestMessage { get; set; }
   5:  
   6:     public HttpStatusCode      StatusCode { get; set; }
   7:     public string              ReasonPhrase { get; set; }
   8:     public bool                IsSuccessStatusCode { get; }
   9:     public HttpResponseHeaders Headers { get; }
  10:     public Version             Version { get; set; }    
  11:     public HttpContent         Content { get; set; }
  12: }

 

二、HttpRouteData

當(dāng)我們調(diào)用某個(gè)Route的GetRouteData的時(shí)候,如果指定的HTTP上下文具有一個(gè)與自身URL模板相匹配,同時(shí)滿足定義的所有約束條件的情況下會(huì)返回一個(gè)RouteData對(duì)象。ASP.NET的路由系統(tǒng)通過RouteData對(duì)象來封裝解析出來的路由數(shù)據(jù),其核心自然是通過Values和DataTokens屬性封裝的路由變量。

ASP.NET Web API用于封裝路由數(shù)據(jù)的對(duì)象被稱為HttpRouteData,其類型實(shí)現(xiàn)了具有如下定義的接口IHttpRouteData。IHttpRouteData接口的定義可比RouteData要簡單很多,它只有兩個(gè)只讀的屬性。Route屬性表示生成該HttpRouteData的Route,而字典類型的屬性Values表示解析出來的路由變量,變量名和變量值對(duì)應(yīng)著該字典對(duì)象的Key和Value。

   1: public interface IHttpRouteData
   2: {
   3:     IHttpRoute                      Route { get; }
   4:     IDictionary<string, object>     Values { get; }
   5: }

在ASP.NET Web API路由系統(tǒng)中唯一實(shí)現(xiàn)了IHttpRouteData接口的公有類型為HttpRouteData,具體的定義如下所示。HttpRouteData實(shí)現(xiàn)的兩個(gè)只讀屬性直接在構(gòu)造函數(shù)中初始化,用于初始化Values屬性的參數(shù)values的類型為HttpRouteValueDictionary,通過如下的代碼片斷可以看到它直接繼承了Dictionary<string, object>,也就是說HttpRouteData對(duì)象具體返回的是一個(gè)類型為HttpRouteValueDictionary的對(duì)象。如果調(diào)用另一個(gè)構(gòu)造函數(shù)(只包含一個(gè)唯一的參數(shù)route),其Values屬性會(huì)初始化成一個(gè)不包含任何元素的空HttpRouteValueDictionary對(duì)象。

   1: public class HttpRouteData : IHttpRouteData
   2: {    
   3:     public HttpRouteData(IHttpRoute route);
   4:     public HttpRouteData(IHttpRoute route, HttpRouteValueDictionary values);
   5:  
   6:     public IHttpRoute                      Route { get; }
   7:     public IDictionary<string, object>     Values { get; }
   8: }
   9:  
  10: public class HttpRouteValueDictionary : Dictionary<string, object>
  11: {
  12:     public HttpRouteValueDictionary();
  13:     public HttpRouteValueDictionary(IDictionary<string, object> dictionary);
  14:     public HttpRouteValueDictionary(object values);
  15: }

 

三、HttpVirtualPathData

在ASP.NET 路由系統(tǒng)中,當(dāng)我們調(diào)用Route的GetVirtualPath方法根據(jù)定義在路由本身的URL模板和指定的路由變量生成一個(gè)完整的URL的時(shí)候,在URL模板與提供的路由變量相匹配的情況下會(huì)返回一個(gè)VirtualPathData對(duì)象,我們可以通過其VirtualPath屬性得到生成的URL。

在ASP.NET Web API路由系統(tǒng)中與VirtualPathData對(duì)應(yīng)的對(duì)象被稱為HttpVirtualPathData,它實(shí)現(xiàn)了具有如下定義的接口IHttpVirtualPathData。對(duì)于定義在IHttpVirtualPathData接口中的兩個(gè)屬性,只讀屬性自然返回的是生成該HttpVirtualPathData對(duì)象的Route,另一個(gè)屬性VirtualPath(改屬性是可讀可寫的)返回生成的URL字符串。

   1: public interface IHttpVirtualPathData
   2: {
   3:     IHttpRoute     Route { get; }
   4:     string         VirtualPath { get; set; }
   5: }

在ASP.NET Web API的應(yīng)用編程接口中定義了如下一個(gè)類型HttpVirtualPathData,它是實(shí)現(xiàn)了接口IHttpVirtualPathData的唯一公有類型。

   1: public class HttpVirtualPathData : IHttpVirtualPathData
   2: {
   3:     public HttpVirtualPathData(IHttpRoute route, string virtualPath);
   4:  
   5:     public IHttpRoute     Route { get; }
   6:     public string         VirtualPath { get; set; }
   7: }

 

四、HttpRouteConstraint

一個(gè)Route能夠與HTTP請(qǐng)求相匹配,必須同時(shí)滿足兩個(gè)條件:其一,請(qǐng)求的URL必須與Route自身的URL的模式相匹配;其二,當(dāng)前請(qǐng)求必須通過定義在當(dāng)前Route上的所有約束。ASP.NET Web API路由系統(tǒng)通過HttpRouteContraint表示路由約束,具體類型實(shí)現(xiàn)了具有如下定義的接口IHttpRouteConstraint。

   1: public interface IHttpRouteConstraint
   2: {
   3:     bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection);
   4: }

HTTP請(qǐng)求是否滿足HttpRouteContraint的約束通過調(diào)用定義在IHttpRouteConstraint的唯一的方法Match來決定,在這里被驗(yàn)證的請(qǐng)求(參數(shù)request)通過HttpRequestMessage對(duì)象來表示。 參數(shù)route代表當(dāng)前HttpRouteContraint所在的Route。

基于HttpRouteContraint的約束是針對(duì)某個(gè)路由變量的,參數(shù)parameterName實(shí)際上代表的就是變量的名稱。由于大部分路由變量會(huì)映射為定義在HttpController中某個(gè)Action方法的參數(shù),所以這里的參數(shù)名為parameterName。當(dāng)ASP.NET Web API框架實(shí)施約束檢驗(yàn)的時(shí)候,已經(jīng)通過URL模板匹配得到了所有的路由變量值,參數(shù)values表示的字典對(duì)象存放了這些路由變量,其Key和Value分別代表路由變量的名稱和值。

通過對(duì)ASP.NET 路由系統(tǒng)的介紹我們知道URL路由具有兩個(gè)“方向”上的應(yīng)用,分別是匹配“入?!闭?qǐng)求并得到相應(yīng)的路由數(shù)據(jù),以及根據(jù)定義的路由規(guī)則和提供的路由變量生成“出?!盪RL。ASP.NET路由系統(tǒng)通過枚舉RouteDirection表示這兩種“路由方向”,而ASP.NET Web API路由系統(tǒng)中的“路由方向”則通過具有如下定義的HttpRouteDirection枚舉來表示。Match方法的參數(shù)routeDirection就是這么一個(gè)枚舉對(duì)象。

   1: public enum HttpRouteDirection
   2: {
   3:     UriResolution,
   4:     UriGeneration
   5: }

我們知道HTTP方法在面向資源的REST架構(gòu)中具有重要的地位和作用,它體現(xiàn)了針對(duì)目標(biāo)資源的操作類型,很多情況下我們?cè)谶M(jìn)行路由注冊(cè)過程中指定的URL模板都是針對(duì)具體某一種或幾種HTTP方法的。ASP.NET路由系統(tǒng)定義了一個(gè)HttpMethodConstraint類型是實(shí)現(xiàn)針對(duì)HTTP方法的約束,ASP.NET Web API的路由系統(tǒng)中則定義了如下一個(gè)同名類型實(shí)現(xiàn)類似的功能。

   1: public class HttpMethodConstraint : IHttpRouteConstraint
   2: {
   3:     public HttpMethodConstraint(params HttpMethod[] allowedMethods);
   4:  
   5:     protected virtual bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection);
   6:     bool IHttpRouteConstraint.Match(HttpRequestMessage request, IHttpRoute route, 
   7:     string parameterName, IDictionary<string, object> values, 
   8:     HttpRouteDirection routeDirection);
   9:  
  10:     public Collection<HttpMethod> AllowedMethods { get; }
  11: }

HttpMethodConstraint的只讀屬性AllowedMethods返回一個(gè)元素類型為HttpMethod的集合,它代表了允許的HTTP方法列表。Match方法從表示請(qǐng)求的HttpRequestMessage對(duì)象中獲得當(dāng)前的HTTP方法,根據(jù)它是否在允許的列表之內(nèi)從而做出是否滿足約束的最終判斷。

除了HttpMethodConstraint,在ASP.NET Web API路由系統(tǒng)的應(yīng)用編程接口中還定義了一系列的約束類型,比如用于驗(yàn)證數(shù)據(jù)類型的IntRouteConstraint、FloatRouteConstraint和BoolRouteConstraint等,用于驗(yàn)證字符串長度的LengthRouteConstraint、MinLengthRouteConstraint和MaxLengthRouteConstraint等。這一系列的HttpMethodConstraint類型其實(shí)是為基于特性(Attribute)的路由而設(shè)計(jì)的,但是由于它們實(shí)現(xiàn)了IHttpRouteConstraint接口,所以在這里它們依然是可用的。

五、HttpRoute

ASP.NET路由系統(tǒng)中的Route的類型均為RouteBase的子類。從前面針對(duì)HttpRouteData和HttpVirtualPathDatad的介紹,我們知道ASP.NET Web API路由系統(tǒng)的RouteHttpRoute的類型實(shí)現(xiàn)了接口IHttpRoute,其定義如下。IHttpRoute的只讀屬性RouteTemplate表示定義的URL模板。兩個(gè)字典類型的只讀屬性Constraints和Defaults表示為路由變量定義的約束和默認(rèn)值,字典的Key和Value分別表示變量名稱和約束/默認(rèn)值。另一個(gè)同樣通過字典類型表示的只讀屬性DataTokens,我們應(yīng)該不會(huì)感到陌生,至于通過制度屬性Handler返回的HttpMessageHandler對(duì)象是組成ASP.NET Web API消息處理管道的核心,我們會(huì)在后續(xù)的文章中對(duì)它進(jìn)行詳細(xì)介紹。

   1: public interface IHttpRoute
   2: {
   3:     string                          RouteTemplate { get; }
   4:     IDictionary<string, object>     Constraints { get; }
   5:     IDictionary<string, object>     Defaults { get; }
   6:     IDictionary<string, object>     DataTokens { get; }
   7:     HttpMessageHandler              Handler { get; }
   8:  
   9:     IHttpRouteData GetRouteData(string virtualPathRoot, HttpRequestMessage request);
  10:     IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values);
  11: }

HttpRoute的作用體現(xiàn)在兩點(diǎn):對(duì)請(qǐng)求的URL進(jìn)行解析并生成封裝路由數(shù)據(jù)的HttpRouteData對(duì)象,以及將提供的路由變量綁定到URL模板以生成一個(gè)完整的URL,這兩個(gè)功能分別通過調(diào)用IHttpRoute的方法GetRouteData和GetVirtualPath來實(shí)現(xiàn)。GetRouteData方法的參數(shù)virtualPathRoot表示虛擬根路徑,一般來說當(dāng)通過HttpRequestMessage獲取的真正請(qǐng)求路徑后需要剔除這個(gè)根路徑部分得到一個(gè)相對(duì)路徑,基于URL模板的匹配應(yīng)該針對(duì)這個(gè)相對(duì)路徑來進(jìn)行。

ASP.NET Web API路由系統(tǒng)中直接實(shí)現(xiàn)了接口IHttpRoute的唯一類型是具有如下定義的HttpRoute。HttpRoute實(shí)現(xiàn)的5個(gè)只讀屬性都可以直接通過調(diào)用相應(yīng)的構(gòu)造函數(shù)進(jìn)行初始化,對(duì)于3個(gè)字典類型的屬性(Constraints、DataTokens和Defaults),如果不曾在構(gòu)造函數(shù)中通過對(duì)應(yīng)的參數(shù)來指定(或者指定的對(duì)象為Null),它們會(huì)被初始化為一個(gè)空的HttpRouteValueDictionary對(duì)象。

   1: public class HttpRoute : IHttpRoute
   2: {
   3:     public HttpRoute();
   4:     public HttpRoute(string routeTemplate);
   5:     public HttpRoute(string routeTemplate, HttpRouteValueDictionary defaults);
   6:     public HttpRoute(string routeTemplate, HttpRouteValueDictionary defaults, HttpRouteValueDictionary constraints);
   7:     public HttpRoute(string routeTemplate, HttpRouteValueDictionary defaults, HttpRouteValueDictionary constraints, HttpRouteValueDictionary dataTokens);
   8:     public HttpRoute(string routeTemplate, HttpRouteValueDictionary defaults, HttpRouteValueDictionary constraints, HttpRouteValueDictionary dataTokens, HttpMessageHandler handler);
   9:  
  10:     public virtual IHttpRouteData GetRouteData(string virtualPathRoot, HttpRequestMessage request);
  11:     public virtual IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values);
  12:     
  13:     public IDictionary<string, object>     Constraints { get; }
  14:     public IDictionary<string, object>     DataTokens { get; }
  15:     public IDictionary<string, object>     Defaults { get; }
  16:     public HttpMessageHandler              Handler { get; }
  17:     public string                          RouteTemplate { get; }
  18: }

現(xiàn)在我們來簡單討論一下實(shí)現(xiàn)在GetRouteData方法中的路由匹配規(guī)則以及最終路由數(shù)據(jù)如何生成。HttpRoute首先根據(jù)表示請(qǐng)求的HttpRequestMessage對(duì)象的RequestUri屬性得到請(qǐng)求地址,一般來說這是一個(gè)包含網(wǎng)絡(luò)協(xié)議前綴(http://或者h(yuǎn)ttps://)和主機(jī)名稱的完整URL。然后HttpRoute會(huì)從該URL中提取路徑部分,并加上“/”前綴。比如說請(qǐng)求地址為“http://www./webapi/products/001”,最終得到的相對(duì)URL為“/webapi/products/001”。

如果GetRouteData方法中通過virtualPathRoot指定了一個(gè)根路徑,如果這個(gè)路徑不是上面得到的相對(duì)URL的前綴(比如“/webservice”),那么匹配失敗并直接返回Null。HttpRoute會(huì)從這個(gè)相對(duì)URL中將這個(gè)根路徑部分剔除掉,最終得到的URL與自身定義的URL模板進(jìn)行模式匹配。比如說,如果指定的根路徑為“/webapi”,那么最終與URL模板進(jìn)行匹配的相對(duì)URL為“products/001”。如果請(qǐng)求URL不符合URL模板的模式,HttpRoute會(huì)直接返回Null。

基于URL模板的模式匹配成功之后,解析出來的路由變量會(huì)保存到一個(gè)字典對(duì)象中。HttpRoute接下來需要檢驗(yàn)通過URL模板驗(yàn)證的請(qǐng)求是否滿足自身定義的所有約束。從上面給出的關(guān)于接口IHttpRoute的定義我們知道表示針對(duì)路由變量約束的列表的屬性Constraints不是IDictionary<string, IHttpRouteConstraint>,而是IDictionary<string, object>。字典對(duì)象的Key代表路由變量的名稱,其Value可以是一個(gè)真正的HttpRouteContraint對(duì)象,也可以是針對(duì)某種類型HttpRouteContraint的字符串表達(dá)式。

如果保存在Constraints屬性中的一個(gè)真正的HttpRouteContraint,HttpRoute會(huì)直接調(diào)用它的Match方法對(duì)請(qǐng)求進(jìn)行相應(yīng)的約束檢驗(yàn),作為參數(shù)parameterName和values傳入的分別是對(duì)應(yīng)的Key和通過URL模板匹配解析出來的路由變量。如果保存在Constraints中的是針對(duì)某種HttpRouteContraint類型的字符串表達(dá)式,HttpRoute會(huì)據(jù)此創(chuàng)建對(duì)應(yīng)的HttpRouteContraint對(duì)象對(duì)請(qǐng)求予以驗(yàn)證。由于這些HttpRouteContraint主要是針對(duì)“特性路由”而設(shè)計(jì)的,對(duì)于每個(gè)HttpRouteContraint的表達(dá)式各自具有怎樣的格式,我們會(huì)在本書第3章“基于標(biāo)注特性的路由”中進(jìn)行詳細(xì)介紹。

如果指定的表示請(qǐng)求的HttpRequestMessage通過了所有HttpRouteContraint的檢驗(yàn),HttpRoute會(huì)根據(jù)解析出來的以字典形式表示的路由變量生成一個(gè)HttpRouteData并作為GetRouteData的返回值,該HttpRouteData對(duì)象的Route屬性就是對(duì)它自身的引用。

我們可以通過一個(gè)簡單的實(shí)例來演示HttpRoute對(duì)請(qǐng)求的路由匹配與檢驗(yàn)規(guī)則。我們?cè)谝粋€(gè)空的ASP.NET MVC應(yīng)用中定義了如下一個(gè)HomeController。在默認(rèn)的Action方法中我們創(chuàng)建了一個(gè)HttpRoute對(duì)象,它的URL模板為“movies/{genre}/{title}/{id}”(針對(duì)某一個(gè)電影,定義其中的三個(gè)變量分別表示電影的類型、片名和ID),而HTTP方法被設(shè)置為HTTP-POST。我們?yōu)榇薍ttpRoute添加了一個(gè)HttpMethodConstraint類型的約束,并將允許的HTTP方法限定為HTTP-POST。

   1: public class HomeController : Controller
   2: {
   3:     public ActionResult Index()
   4:     {
   5:         string routeTemplate = "movies/{genre}/{title}/{id}";
   6:         IHttpRoute route = new HttpRoute(routeTemplate);
   7:         route.Constraints.Add("httpMethod", new HttpMethodConstraint(HttpMethod.Post));
   8:  
   9:         HttpRequestMessage request1 = new HttpRequestMessage(HttpMethod.Get, "http://www./products/movies/romance/titanic/r001");
  10:         HttpRequestMessage request2 = new HttpRequestMessage(HttpMethod.Post, "http://www./products/movies/romance/titanic/r001");
  11:  
  12:         string virtualPathRoot1 = "/";
  13:         string virtualPathRoot2 = "/products/";
  14:  
  15:         IHttpRouteData routeData1 = route.GetRouteData(virtualPathRoot1, request1);
  16:         IHttpRouteData routeData2 = route.GetRouteData(virtualPathRoot1, request2);
  17:         IHttpRouteData routeData3 = route.GetRouteData(virtualPathRoot2, request1);
  18:         IHttpRouteData routeData4 = route.GetRouteData(virtualPathRoot2, request2);
  19:  
  20:         return View(new bool[] { routeData1 != null, routeData2 != null, routeData3 != null, routeData4 != null });
  21:     }
  22: }

我們創(chuàng)建了兩個(gè)HttpRequestMessage對(duì)象作為被檢驗(yàn)的HTTP請(qǐng)求,它們具有相同的請(qǐng)求地址(“http://www./products/movies/romance/titanic/r001”)不同的HTTP方法(HTTP-GET和HTTP-POST)。為了驗(yàn)證指定不同的虛擬根路徑對(duì)HttpRoute路由解析的影響,我們分別定義了兩個(gè)不同的根路徑(“/”和“/products/”)。針對(duì)兩個(gè)不同的請(qǐng)求和根路徑的組合,我們4次調(diào)用了HttpRoute的GetRouteData方法,通過判斷返回的HttpRouteData是否為Null來判斷對(duì)應(yīng)的請(qǐng)求針對(duì)給定的根路徑是否與定義在HttpRoute中的路由規(guī)則相匹配。

Action方法Index最終將默認(rèn)的View呈現(xiàn)出來,指定的Model是一個(gè)布爾類型元素的數(shù)組,每個(gè)一個(gè)布爾值代表對(duì)應(yīng)的請(qǐng)求與根路徑組合是否通過了HttpRoute的檢驗(yàn)。如下所示的就是對(duì)應(yīng)View的定義,這是一個(gè)Model類型為bool[]的強(qiáng)類型View,我們將代表檢驗(yàn)結(jié)果的布爾值以表格的形式呈現(xiàn)出來。

   1: @model bool[]
   2: <html>
   3: <head>
   4:     <title>路由解析</title>
   5: </head>
   6: <body>
   7:     <table>
   8:         <tr>
   9:             <th></th>
  10:             <th>HTTP-GET</th>
  11:             <th>HTTP-POST</th>
  12:         </tr>
  13:         <tr>
  14:             <td>/</td>
  15:             <td>@Model[0]</td>
  16:             <td>@Model[1]</td>
  17:         </tr>
  18:         <tr>
  19:             <td>/products/</td>
  20:             <td>@Model[2]</td>
  21:             <td>@Model[3]</td>
  22:         </tr>
  23:     </table>
  24: </body>
  25:     </html>

image

直接運(yùn)行該程序后會(huì)在瀏覽器中呈現(xiàn)出如右圖所示的輸出結(jié)果,針對(duì)兩個(gè)基于不同HTTP方法的請(qǐng)求和兩個(gè)不同虛擬根路徑的組合,只有最后一組能夠完全符合定義在HttpRoute中的路由規(guī)則,由此可以看出上面我們介紹的URL模板、約束以及指定的虛擬根路徑對(duì)HttpRoute路由解析的影響。

HttpRoute的GetRouteData方法解決了針對(duì)“入棧”請(qǐng)求的檢驗(yàn),接下來我們來討論HttpRoute在另一個(gè)“路由方向”上的應(yīng)用,即根據(jù)定義的路由規(guī)則和給定的路由變量生成一個(gè)完整的URL。針對(duì)生成URL的路由解析實(shí)現(xiàn)在GetVirtualPath方法中,我們現(xiàn)在來詳細(xì)介紹用于封裝生成URL的HttpVirtualPathData是如何生成出來的。

   1: public class HttpRoute : IHttpRoute
   2: {
   3:     //其他成員
   4:     public virtual IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values);
   5: }

如上面的代碼片斷所示,HttpRoute的GetVirtualPath方法具有兩個(gè)參數(shù),分別是表示請(qǐng)求的HttpRequestMessage對(duì)象和用于替換掉定義在URL模板中路由變量占位符的“值”。HttpRoute能夠根據(jù)模板生成一個(gè)完整的URL取決于是否能夠提供定義在URL模板中所有路由變量占位符的值,而這個(gè)路由變量值具有如下三個(gè)來源。

  • 調(diào)用GetVirtualPath參數(shù)傳入的字典類型的參數(shù)values。
  • 附加到HttpRequestMessage對(duì)象屬性列表(對(duì)應(yīng)于它的Properties屬性)中的HttpRouteData對(duì)象的Values屬性表示字典。
  • HttpRoute定義的默認(rèn)值。

上述的這個(gè)列表順序也體現(xiàn)了HttpRoute對(duì)象在提取路由變量值過程中的選擇優(yōu)先級(jí)。換句話說,如果同名變量值同時(shí)存在于上述的三個(gè)或者兩個(gè)數(shù)據(jù)源,排在前面的會(huì)被優(yōu)先選擇。

至于如何將封裝路由數(shù)據(jù)的HttpRoute對(duì)象附加到某個(gè)HttpRequestMessage對(duì)象上,實(shí)際上就是將對(duì)象添加到HttpRequestMessage的Properties屬性表示的字典對(duì)象中,ASP.NET Web API的路由系統(tǒng)為它限定了一個(gè)固定的Key值為“MS_HttpRouteData”,我們可以通過如下所示的定義在靜態(tài)類型HttpPropertyKeys中的只讀字段HttpRouteDataKey得到這個(gè)值。除此之外,我們還可以調(diào)用針對(duì)HttpRequestMessage類型的兩個(gè)擴(kuò)展方法GetRouteData/SetRouteData來提取和設(shè)置HttpRouteData。

   1: public static class HttpPropertyKeys
   2: {
   3:     //其他成員
   4:     public static readonly string HttpRouteDataKey;
   5: }
   6:  
   7: public static class HttpRequestMessageExtensions
   8: {
   9:     //其他成員
  10:     public static IHttpRouteData GetRouteData(this HttpRequestMessage request);
  11:     public static void SetRouteData(this HttpRequestMessage request, IHttpRouteData routeData);
  12: }

如果HttpRoute在上述三個(gè)來源中不能完全獲取用于替換定義在URL模板中的所有路由變量占位符,它會(huì)直接返回Null。即使能夠完全獲得這些變量值,它還有一個(gè)很“隱晦”的條件:要求參數(shù)values表示的字典對(duì)象中必須包含一個(gè)Key值為“httproute”的元素,否則會(huì)認(rèn)為提供的對(duì)象并非一個(gè)有效的能夠提供“路由變量值”的字典。至于這個(gè)特殊的Key值,我們可以通過定義在類型HttpRoute中如下一個(gè)靜態(tài)只讀字段HttpRouteKey來獲得。

   1: public class HttpRoute : IHttpRoute
   2: {
   3:     //其他成員
   4:     public static readonly string HttpRouteKey = "httproute";
   5: }

當(dāng)HttpRoute根據(jù)優(yōu)先級(jí)從上述三個(gè)數(shù)據(jù)源中獲取到以字典對(duì)象表示的所有路由變量值之后,還需要檢驗(yàn)它們是否能夠滿足自身定義的所有約束,如果不滿足任何一個(gè)約束,HttpRoute依然會(huì)直接返回Null。當(dāng)?shù)玫降穆酚勺兞恐档玫搅怂屑s束的檢驗(yàn),這些值會(huì)綁定到URL模板生成一個(gè)完整的URL,最終被封裝成類型為HttpVirtualPathData的對(duì)象返回。

為了使讀者能夠?qū)Χx在HttpRoute的GetVirtualPath方法中的路由解析邏輯具有更加深刻的印象,我們來做一個(gè)簡單的實(shí)例演示。我們?cè)谝粋€(gè)空的ASP.NET MVC應(yīng)用中定義了如下一個(gè)HomeController,在默認(rèn)的Action方法Index中將5次調(diào)用HttpRoute對(duì)象的GetVirtualPath方法返回的HttpVirtualPathData對(duì)象呈現(xiàn)在默認(rèn)的View中。

   1: public class HomeController : Controller
   2: {
   3:     public ActionResult Index()
   4:     {
   5:         string routeTemplate = "weather/{areacode}/{days}";
   6:         IHttpRoute route = new HttpRoute(routeTemplate);
   7:         route.Constraints.Add("httpMethod", 
   8:             new HttpMethodConstraint(HttpMethod.Post));
   9:         route.Defaults.Add("days", 2);
  10:  
  11:         List<IHttpVirtualPathData> virutualPathList = 
  12:             new List<IHttpVirtualPathData>();
  13:         HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "/");
  14:  
  15:         //1. 不能提供路由變量areacode的值
  16:         Dictionary<string, object> values = new Dictionary<string, object>();
  17:         virutualPathList.Add(route.GetVirtualPath(request, values));
  18:  
  19:         //2. values無Key為"httproute"的元素
  20:         values.Add("areaCode", "028");
  21:         virutualPathList.Add(route.GetVirtualPath(request, values));
  22:  
  23:         //3. 所有的路由變量值通過values提供
  24:         values.Add("httproute", true);
  25:         values.Add("days", 3);
  26:         IHttpRouteData routeData = new HttpRouteData(route);
  27:         routeData.Values.Add("areacode", "0512");
  28:         routeData.Values.Add("days", 4);
  29:         request.SetRouteData(routeData);
  30:         virutualPathList.Add(route.GetVirtualPath(request, values));
  31:  
  32:         //4. 所有的路由變量值通過request提供
  33:         values.Clear();
  34:         values.Add("httproute", true);           
  35:         virutualPathList.Add(route.GetVirtualPath(request, values));
  36:  
  37:         //5. 采用定義在HttpRoute上的默認(rèn)值(days = 2)
  38:         routeData.Values.Remove("days");
  39:         virutualPathList.Add(route.GetVirtualPath(request, values));
  40:  
  41:         return View(virutualPathList.ToArray());
  42:     }
  43: }

如上面的代碼片斷所示,我們針對(duì)URL模板“weather/{areacode}/{days}”創(chuàng)建了一個(gè)HttpRoute對(duì)象,其中路由變量days具有默認(rèn)值2。除此之外,我們?yōu)閯?chuàng)建的HttpRoute添加了一個(gè)HttpMethodConstraint類型的約束將允許的HTTP方法限定為HTTP-POST。我們隨后創(chuàng)建了基于HTTP-GET的HttpRequestMessage對(duì)象,其請(qǐng)求地址為“/”。

第一次調(diào)用GetVirtualPath方法傳入的參數(shù)分別是上面創(chuàng)建的HttpRequestMessage和一個(gè)空的字典對(duì)象values,很顯然在此情況下HttpRoute不能為路由變量areaCode獲取相應(yīng)的替換值。對(duì)于第二次調(diào)用,傳入的字典對(duì)象為路由變量areaCode指定了相應(yīng)的值。

在第三次調(diào)用中,變量values表示的字典對(duì)象不僅僅同時(shí)包含了路由變量areaCode和days的值,還添加了一個(gè)Key和Value分別為“httproute”和True的元素。對(duì)于提供的HttpRequestMessage對(duì)象,我們通過調(diào)用擴(kuò)展方法SetRouteData為它設(shè)置了一個(gè)HttpRouteData對(duì)象,該對(duì)象的Values屬性表示的字典中同樣具有areaCode和days這兩個(gè)路由變量的值。

我們?cè)诘谒拇握{(diào)用GetVirtualPath方法之前將values變量保存的路由變量areaCode和days的值清除,但保留了Key為“httproute”的元素。對(duì)于最后一次GetVirtualPath方法調(diào)用,我們清楚了附加在HttpRequestMessage上HttpRouteData對(duì)象針對(duì)路由變量days的值。

如下所示的是Action方法Index對(duì)應(yīng)View的定義,這是一個(gè)Model類型為IHttpVirtualPathData數(shù)組的強(qiáng)類型View。在該View中,我們將每個(gè)HttpVirtualPathData對(duì)象的VirtualPath屬性表示的URL以表格的形式呈現(xiàn)出來。如果HttpVirtualPathData為Null,直接顯示“N/A”字樣。

   1: @model System.Web.Http.Routing.IHttpVirtualPathData[]
   2: <html>
   3:     <head>
   4:         <title>路由解析</title>
   5:     </head>
   6:     <body>
   7:         <table>
   8:             @for (int i = 0; i < Model.Length; i++)
   9:             { 
  10:                 <tr>
  11:                     <td>@(i+1)</td>
  12:                     <td>@(Model[i] == null ? "N/A" : Model[i].VirtualPath)</td>
  13:                 </tr>
  14:             }
  15:         </table>
  16:     </body>
  17: </html>

image直接運(yùn)行該程序后會(huì)在瀏覽器中呈現(xiàn)出如右圖所示的輸出結(jié)果,它充分驗(yàn)證了上面我們介紹的實(shí)現(xiàn)在HttpRoute的GetVirtualPath方法中的路由解析邏輯。對(duì)于第一、二次針對(duì)HttpRoute的GetVirtualPath方法的調(diào)用,由于不滿足“必須提供定義在URL模板中所有路由變量值”和“提供路由變量值的字典必須包含一個(gè)Key為httproute的元素”的條件,所以直接返回Null。最后三次針對(duì)GetVirtualPath方法的調(diào)用印證了上面我們介紹的“路由變量數(shù)據(jù)源選擇優(yōu)先級(jí)”的論述。

其實(shí)這個(gè)實(shí)例還說明了另一個(gè)問題:HttpRoute的GetVirtualPath方法只會(huì)進(jìn)行針對(duì)定義在URL模板中路由變量的約束檢驗(yàn)。對(duì)于這個(gè)演示實(shí)例來說,我們創(chuàng)建的HttpRoute具有一個(gè)基于HTTP-POST的HttpMethodConstraint類型的約束(對(duì)應(yīng)的名稱為“httpMethod”),但是調(diào)用GetVirtualPath方法傳入的確是一個(gè)針對(duì)HTTP-GET的HttpRequestMessage對(duì)象,依然是可以生成相應(yīng)HttpVirtualPathData的。這也很好理解,因?yàn)镠ttpRoute的GetVirtualPath方法的目的在于生成一個(gè)合法的URL,定義在URL模板中的路由變量對(duì)應(yīng)的約束才有意義。

六、HttpRouteCollection

故名思義HttpRouteCollection就是一個(gè)元素類型為IHttpRoute的集合,如下面的代碼片斷所示,它實(shí)現(xiàn)了接口ICollection<IHttpRoute>。ASP.NET Web API路由系統(tǒng)中的路由表實(shí)際上就是一個(gè)HttpRouteCollection對(duì)象。HttpRouteCollection具有一個(gè)只讀屬性VirtualPathRoot表示進(jìn)行路由解析時(shí)默認(rèn)使用的虛擬跟路徑,該屬性可以直接在調(diào)用構(gòu)造函數(shù)是通過參數(shù)指定,其默認(rèn)值為“/”。

   1: public class HttpRouteCollection : ICollection<IHttpRoute>, IDisposable
   2: {
   3:     //其他成員
   4:     public HttpRouteCollection();
   5:     public HttpRouteCollection(string virtualPathRoot);    
   6:    
   7:     public IHttpRoute CreateRoute(string routeTemplate, object defaults, object constraints);
   8:     public IHttpRoute CreateRoute(string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens);
   9:     public virtual IHttpRoute CreateRoute(string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler);
  10:     
  11:     public virtual IHttpRouteData GetRouteData(HttpRequestMessage request);
  12:     public virtual IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, string name, IDictionary<string, object> values);
  13:  
  14:     public virtual string VirtualPathRoot { get; }
  15: }

除了實(shí)現(xiàn)定義在接口ICollection<IHttpRoute>中的眾多方法之外,HttpRouteCollection還定義了兩個(gè)CreateRoute方法重載幫助我們根據(jù)指定的URL模板、路由變量默認(rèn)值、約束和DateToken列表以及HttpMessageHandler對(duì)象創(chuàng)建HttpRoute對(duì)象。

HttpRouteCollection同樣定義了GetRouteData和GetVirtualPath方法,它們的邏輯與ASP.NET路由系統(tǒng)中的RouteCollection類型中的同名方法一致:按照先后順利調(diào)用每個(gè)HttpRoute對(duì)象的同名方法直到返回一個(gè)具體的HttpRouteData或者HttpVirtualPathData對(duì)象。

HttpRouteCollection的GetRouteData方法中并沒有表示虛擬根路徑的參數(shù),那么當(dāng)它在調(diào)用具體HttpRoute對(duì)象的同名方法的時(shí)候如何指定這個(gè)參數(shù)呢?具體的邏輯是這樣的:它先判斷虛擬根路徑是否已經(jīng)被添加到表示請(qǐng)求的HttpRequestMessage的屬性字典(Properties屬性)中,對(duì)應(yīng)的Key為“MS_VirtualPathRoot”,如果這樣的屬性存在并且是一個(gè)字符串,那么這將直接被用作調(diào)用HttpRoute的GetRouteData方法的參數(shù)。否則直接使用通過屬性VirtualPathRoot表示的默認(rèn)根路徑。

HttpRequestMessage屬性字典中表示虛擬根路徑的Key可以直接通過類型HttpPropertyKeys的靜態(tài)只讀字段VirtualPathRoot獲取。我們可以直接調(diào)用HttpRequestMessage如下兩個(gè)擴(kuò)展方法GetVirtualPathRoot和SetVirtualPathRoot獲取或者設(shè)置虛擬根路徑。

   1: public static class HttpPropertyKeys
   2: {
   3:     //其他成員
   4:     public static readonly string VirtualPathRoot;
   5: }
   6:  
   7: public static class HttpRequestMessageExtensions
   8: {
   9:     //其他成員
  10:     public static string GetVirtualPathRoot(this HttpRequestMessage request);
  11:     public static void SetVirtualPathRoot(this HttpRequestMessage request, string virtualPathRoot);
  12: }

關(guān)于HttpRouteCollection,值得一提的是它對(duì)于添加的HttpRoute對(duì)象的保存方式。如下面的代碼片斷所示,HttpRouteCollection具有_collection和_dictionary兩個(gè)只讀字段,類型分別是List<IHttpRoute>和IDictionary<string, IHttpRoute>,前者單純地保存添加的HttpRoute對(duì)象,后者給每個(gè)添加的HttpRoute對(duì)象匹配一個(gè)具有唯一性的名稱。

   1: public class HttpRouteCollection : ICollection<IHttpRoute>, IDisposable
   2: {
   3:     // 其他成員
   4:     private readonly List<IHttpRoute>                 _collection;
   5:     private readonly IDictionary<string, IHttpRoute>     _dictionary;
   6:    
   7:     public virtual void Insert(int index, string name, IHttpRoute value);
   8:     public virtual void Add(string name, IHttpRoute route);
   9:     void ICollection<IHttpRoute>.Add(IHttpRoute route);
  10:     
  11:     public virtual bool Remove(string name);    
  12:     bool ICollection<IHttpRoute>.Remove(IHttpRoute route);
  13:  
  14:     public virtual IHttpRoute this[int index] { get; }
  15:     public virtual IHttpRoute this[string name] { get; }
  16: }

HttpRouteCollection采用“接口顯式實(shí)現(xiàn)”的方式實(shí)現(xiàn)了定義在ICollection<T>中的Add和Remove方法,所以這兩個(gè)方法我們基本上不用使用。取而代之的是額外的Add和Remove方法,通過調(diào)用Add方法可以為添加的HttpRoute對(duì)象指定一個(gè)“注冊(cè)名稱”,而根據(jù)這個(gè)注冊(cè)名稱可以調(diào)用Remove方法將對(duì)應(yīng)的HttpRoute移除。

調(diào)用Add方法添加的HttpRoute會(huì)同時(shí)被添加到通過字段_collection和_dictionary表示的集合和字典之中。不論是調(diào)用HttpRouteCollection的GetRouteData方法還是GetVirtualPath方法,它總是按照HttpRoute在集合_collection中的順序進(jìn)行便利,第一個(gè)匹配的HttpRoute會(huì)被選用,所以HttpRoute在集合中的順序顯得尤為重要。由于通過Add方法添加的HttpRoute對(duì)象總是被添加到集合的最后,所以另一個(gè)Insert方法被定義在HttpRouteCollection中使我們可以同時(shí)決定被添加HttpRoute的名稱和次序。除了上述這些方法外,我們還可以通過索引的方式得到存在于HttpRouteCollection對(duì)象中的HttpRoute對(duì)象。

七、注冊(cè)路由映射

與ASP.NET路由系統(tǒng)下的路由映射類似,ASP.NET Web API下的路由映射就是為針對(duì)應(yīng)用的路由表添加相應(yīng)HttpRoute對(duì)象的過程。整個(gè)ASP.NET Web API框架是一個(gè)請(qǐng)求處理的管道,我們可以在程序啟動(dòng)的時(shí)候?qū)ζ溥M(jìn)行相應(yīng)的配置是整個(gè)管道按照我們希望的方式來工作,我們所做的擴(kuò)張也是通過相應(yīng)的配置應(yīng)用到管道之上。

我們對(duì)ASP.NET Web API的請(qǐng)求處理管道所做的所有配置基本上都是通過一個(gè)類型為HttpConfiguration的對(duì)象來完成,而路由注冊(cè)自然也不例外。如下面的代碼片斷所示,HttpConfiguration具有一個(gè)類型為HttpRouteCollection的只讀屬性Routes,我們進(jìn)行路由映射注冊(cè)的HttpRoute正是被添加于此。

   1: public class HttpConfiguration : IDisposable
   2: {
   3:     //其他成員
   4:     public HttpRouteCollection                      Routes { get; }
   5:     public string                                   VirtualPathRoot { get; }
   6:     public ConcurrentDictionary<object, object>     Properties { get; }
   7: }

HttpConfiguration的另一個(gè)與路由相關(guān)的屬性VirtualPathRoot表示默認(rèn)使用的虛擬根路徑,它直接返回通過Routes屬性表示的HttpRouteCollection對(duì)象的同名屬性。我們可以通過字典類型的只讀屬性Properties將相應(yīng)的對(duì)象附加到HttpConfiguration,這與我們使用HttpRequestMessage的Properties屬性的方式一致。在具體的運(yùn)行環(huán)境中,我們使用HttpConfiguration都是針對(duì)整個(gè)應(yīng)用的全局對(duì)象,所以我們添加到Properties屬性中的對(duì)象也是全局,我們?cè)谡麄€(gè)應(yīng)用的任何地方都可以提取它們。

我們可以直接根據(jù)指定的URL模板,以及針對(duì)路由變量的默認(rèn)值和約束來創(chuàng)建相應(yīng)的HttpRoute,并最終將其添加到通過HttpConfiguration的Routes對(duì)象表示的路由表中從而到達(dá)注冊(cè)路由映射的目的。除此之外,我們還可以直接調(diào)用HttpRouteCollection如下一系列重載的擴(kuò)展方法MapHttpRoute實(shí)現(xiàn)相同的目的。實(shí)際上這些擴(kuò)展方法最終還是調(diào)用HttpRouteCollection的Add方法將創(chuàng)建的HttpRoute添加到路由表中的。

   1: public static class HttpRouteCollectionExtensions
   2: {
   3:     //其他成員
   4:     public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate);
   5:     public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults);
   6:     public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints);
   7:     public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler);
   8: }

對(duì)于上面定義的這些MapHttpRoute方法重載,最終根據(jù)指定的URL模板、默認(rèn)值、約束、DataToken以及HttpMessageHandler對(duì)具體HttpRoute的創(chuàng)建是通過調(diào)用HttpRouteCollection具有如下定義的CreateRoute方法實(shí)現(xiàn)的。這是一個(gè)虛方法,所以如何我們希望調(diào)用這些擴(kuò)展方法注冊(cè)自定義的HttpRoute,可以自定義一個(gè)HttpRouteCollection類型并重寫這個(gè)CreateRoute方法即可。

   1: public class HttpRouteCollection : ICollection<IHttpRoute>, IDisposable
   2: {
   3:     //其他成員
   4:     public virtual IHttpRoute CreateRoute(string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, 
   5:         IDictionary<string, object> dataTokens, HttpMessageHandler handler);
   6: }

至于如果獲取用于配置ASP.NET Web API管道的HttpConfiguration對(duì)象,這依賴于我們對(duì)Web API的寄宿方式,這并沒有定義在ASP.NET Web API的核心框架之中。

八、缺省路由變量

我們?cè)谶M(jìn)行路由注冊(cè)的時(shí)候可以為某個(gè)路由變量設(shè)置一個(gè)默認(rèn)值,這個(gè)默認(rèn)值可以是一個(gè)具體的變量值,也可以是通過RouteParameter具有如下定義的靜態(tài)只讀字段Optional返回的一個(gè)RouteParameter對(duì)象,我們具有這種默認(rèn)值的路由變量成為缺省路由變量。

   1: public sealed class RouteParameter
   2: {
   3:     public static readonly RouteParameter Optional;
   4: }

實(shí)際上當(dāng)我們利用Visual Studio的ASP.NET Web API向?qū)陆ㄒ粋€(gè)Web應(yīng)用的時(shí)候,在生成的用于注冊(cè)路由的RouteConfig.cs中會(huì)默認(rèn)注冊(cè)如下一個(gè)HttpRoute,其路由變量id就是一個(gè)具有默認(rèn)值為RouteParameter.Optional的缺省路由變量。

   1: public class RouteConfig
   2: {
   3:     public static void RegisterRoutes(RouteCollection routes)
   4:     {
   5:     //其他操作
   6:         routes.MapHttpRoute(
   7:             name            : "DefaultApi",
   8:             routeTemplate   : "api/{controller}/{id}",
   9:             defaults        : new { id = 
RouteParameter.Optional
 }
  10:         );
  11:     }
  12: }

雖然同是具有默認(rèn)值的路由變量,但是缺省路由變量具有不同之處:如果請(qǐng)求URL中沒有提供對(duì)應(yīng)變量的值,普通具有默認(rèn)值的路由變量依然會(huì)出現(xiàn)在最終HttpRouteData的Values屬性中,但是缺省路由變量則不會(huì)。

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

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多