Asp.Net Web API 導航html
Asp.Net Web API第一課——入門http://www.cnblogs.com/aehyok/p/3432158.htmlgit
Asp.Net Web API第二課——CRUD操做http://www.cnblogs.com/aehyok/p/3434578.htmlweb
Asp.Net Web API第三課——.NET客戶端調用Web API http://www.cnblogs.com/aehyok/p/3439698.html正則表達式
Asp.Net Web API第四課——HttpClient消息處理器 http://www.cnblogs.com/aehyok/p/3442277.html算法
Asp.Net Web API第五課——Web API路由 http://www.cnblogs.com/aehyok/p/3442051.htmlapi
前言框架
本文描述ASP.NET Web API如何把一個HTTP請求路由到控制器的一個特定的Action上。關於路由的整體概述能夠參見上一篇教程 http://www.cnblogs.com/aehyok/p/3442051.html。這篇文章主要來學習路由過程的細節。若是你建立了一個Web API項目,發現有一些請求沒有按照你指望的方式被路由,但願這篇文章將對你有所幫助。asp.net
本文主要分爲三個階段:學習
1.匹配URI到一個Route Template。ui
2.選擇一個Controller。
3.選擇一個Action。
你能夠用本身的自定義行爲來替換這一過程當中的某些部分。在本文中,我未來描述默認的行爲。在文章結尾,我會註明能夠在什麼地方自定義行爲。
Route Templates
路由模版看上去相似於一個URI路徑,但它能夠具備佔位符,並用花括號來指示:
"api/{controller}/public/{category}/{id}"
當建立一個路由的時候,你能夠爲某些或全部佔位符提供默認值:
defaults: new { category = "all" }
你也能夠提供約束,它限制URI片斷如何與佔位符匹配:
constraints: new { id = @"\d+" } // Only matches if "id" is one or more digits.
上面語句是經過正則表達式來限制片斷的取值,上面的註釋說明 id片斷只匹配一個或多個數字,所以URI中的id片斷必須是數字才能與這個路由進行匹配。
這個框架試圖把URI路徑中的片斷與這個模板進行匹配。模板中的文字必須嚴格匹配。一個佔位符能夠匹配任何值,除非你指定了約束。這個框架不會匹配URI另外的部分,例如主機名或者一個查詢字符串。這個框架會選擇路由表中第一個匹配的路由。
這裏有兩個特殊的佔位符:「{controller}」和「{action}」。
若是你提供默認值,那麼這個路由將匹配缺乏這些片斷的URI。例如:
routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{category}", defaults: new { category = "all" } );
這個URI「http://localhost/api/products」與這個路由是匹配的。「{category}」片斷被賦成了默認值「all」。
若是這個框架發現了一個匹配的URI,它會建立包含每一個佔位符值的一個字典。這個鍵值是不帶花括號的的佔位符名稱。這個值取自於URI路徑或者是默認值中的。這個字段被存在IHttpRouteData對象中。在匹配路由階段,這個特殊的"{controller}" and "{action}"佔位符的處理和其餘佔位符是同樣的。它們用另外的值被簡單的存儲在字典中。
在默認值中可使用特殊的RouteParameter.Optional值。若是一個佔位符被賦予了這個值,那麼這個值將不會被添加到路由字典中,例如:
routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{category}/{id}", defaults: new { category = "all", id = RouteParameter.Optional } );
對於URI路徑「api/products」,路由字典將含有:controller:"products"、category:"all"。
然而,對於「api/products/toys/123」,路由字典將含有:controller:"products"、category:"toys"、id:"123"。
這個默認值也能夠包含未出如今路由模板中的值。若這條路由匹配,則該值會被存儲在路由字典中。例如:
routes.MapHttpRoute( name: "Root", routeTemplate: "api/root/{id}", defaults: new { controller = "customers", id = RouteParameter.Optional } );
若是URI路徑是「api/root/8」,字典將含有兩個值:controller:「customers」,id:"8"。
Selecting a Controller
控制器選擇是由IHttpControllerSelector.SelectController方法來處理的。這個方法以HttpRequestMessage實例爲參數,並返回HttpControllerDescriptor。
其默認實現是由DefaultHttpControllerSelector類提供的。這個類使用了一種很直接的算法:
1.查找路由字典的「controller」鍵。
2.取得這個鍵的值,並附加字符串「Controller」,以獲得控制器的類型名。
3.用這個類型名查找Web API控制器。
例如,若是路由字典中的鍵-值對爲「controller」=「products」,那麼控制器類型便爲「ProductsController」。若是沒有匹配類型,或有多個匹配,這個框架會給客戶端返回一條錯誤。
對於步驟3,DefaultHttpControllerSelector使用IHttpControllerTypeResolver接口以得到Web API控制器類型的列表。 IHttpControllerTypeResolver的默認實現會返回全部符合如下條件的public類:
a:實現IHttpController的類。
b:是非抽象類。
c:名稱以「Controller」結尾的類。
Action Selection
選擇了控制器以後,這個框架會經過調用IHttpActionSelector.SelectAction方法來選擇動做。這個方法以HttpControllerContext爲參數,並返回HttpActionDescriptor。
這個默認實現是由ApiControllerActionSelector類提供的。爲了選擇一個動做,會查找如下方面:
1.HTTP請求的方法。
2.這個路由模板中的「action」佔位符。
3.控制器中動做的參數。
在查找選擇算法以前,咱們須要理解控制器動做的一些事情。
控制器中的哪些方法被當作爲是「動做」?當選擇一個動做時,這個框架只考察控制器的public實例方法。並且,它會排除特殊名稱的方法(構造器、事件、操做符、重載等等),以及集成自ApiController的類方法。
HTTP Methods
這個框架只會選擇與請求的HTTP方法匹配的動做,肯定以下:
1.你能夠用註解屬性AcceptVerbs、HttpDelete、HttpGet、HttpHead、HttpOptions、HttpPatch、HttpPost、或HttpPut來指定HTTP方法。
2.不然,若是控制器方法名稱以「Get」、「Post」、「Put」、「Delete」、「Head」、「Options」、或「Patch」開頭,那麼根據這個約定,該Action將支持相應的HTTP方法。
3.若是以上都不是,那麼這個方法將支持Post。
Parameter Bindings.
參數綁定是指Web API如何建立參數值。如下是參數綁定的默認規則:1.簡單類型取自URI。2.複雜類型取自請求正文。
簡單類型包括全部「.NET框架簡單類型」,另外還有,DateTime、Decimal、Guid、String和TimeSpan。對於每個動做,最多隻有一個參數能夠讀取請求正文。
它也能夠重寫這種默認的綁定規則。See WebAPI Parameter binding under the hood。
在這種背景下,動做選擇算法以下:
1.建立該控制器中與HTTP請求方法匹配的全部動做的列表。
2.若是路由字典有「action」條目,移除與該條目值不匹配的動做。
3.試圖將動做參數與該URI匹配,以下:
a:針對每一個動做,得到簡單類型的參數列表,這是綁定獲得URI參數的地方。該列表不包括可選參數。
b:從這個列表中,試着在路由字典或是在URI查詢字符串中,找到每一個參數的匹配。匹配是與大小寫無關的,且與參數順序無關。
c:選擇這樣的一個action,在列表中的每一個參數在URI中有一個匹配。
d:若是知足這些條件的動做不止一個,選用參數匹配最多的一個。
4.忽略用[NonAction]註解屬性標註的動做。
第3步可能會讓人困擾。其基本思想是,能夠從URI、或請求體、或一個自定義綁定來獲取參數值。對於來自URI的參數,咱們但願確保URI在其路徑(經過路由字典)或查詢字符串中實際包含了一個用於此參數的值。
例如,考慮如下動做:
public void Get(int id)
其id參數綁定到URI。所以,這個動做只能匹配在路由字典或查詢字符串中包含了「id」值的URI。
可選參數是一個例外,由於它們是可選的。對於可選參數,若是綁定不能經過URI獲取它的值,是不要緊的。
複雜類型是另外一種緣由的例外。一個複雜類型只能經過自定義綁定來綁定到URI。可是在這種狀況下,這個框架不能提早知道是否這個參數被綁定到一個特殊的URI。爲了查明狀況,這個框架須要調用這個綁定。選擇算法的目的是在調用綁定以前根據靜態描述來選擇一個動做。所以,複雜類型是屬於匹配算法以外的。
動做選擇以後,會調用全部參數綁定。
Summary:
1.動做必須匹配請求的HTTP方法。
2.動做名必須匹配路由字典中的「action」條目,若是有。
3.對於動做的各個參數,若是參數取自URI,那麼該參數名必須在路由字典或URI查詢字符串中可以被找到。(可選參數和複雜類型除外)。
4.試圖匹配最多數目的參數。最佳匹配多是一個無參數的方法。
Extended Example
看以下路由:
routes.MapHttpRoute( name: "ApiRoot", routeTemplate: "api/root/{id}", defaults: new { controller = "products", id = RouteParameter.Optional } ); routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
再看以下Contoller下的內容:
public class ProductsController : ApiController { public IEnumerable<Product> GetAll() {} public Product GetById(int id, double version = 1.0) {} [HttpGet] public void FindProductsByName(string name) {} public void Post(Product value) {} public void Put(int id, Product value) {} }
HTTP請求:
http://localhost:34701/api/products/1?version=1.5&details=1
路由匹配:
該URI與名爲「DefaultApi」路由匹配。路由字典包含如下條目:controller:"products",id:"1"。該路由字典並未包含查詢字符串參數「version」和「details」,但這些將在動做選擇期間考慮。
控制器選擇:
根據路由字典中的「controller」條目,控制器類型是ProductsController。
動做選擇:
這個HTTP請求是一個GET請求。支持Get的控制器動做是GetALL、GetById、FindProductsByName。這個路由字典不包含」action「條目,所以不須要匹配動做名稱。
下一步,會試圖匹配這些動做的參數名,只考查GET動做。
注意,不會考慮GetById的version參數,由於它是一個可選參數。
GetAll方法很是匹配。GetById方法也匹配,由於路由字典包含了「id」。FindProductsByName方法不匹配。
GetById方法是贏家,由於它匹配了一個參數,而GetAll無參數。該方法將以如下參數值被調用:id=1,version=1.5
注意,雖然version未被用於選擇算法,但該參數值會取自URI查詢字符串。
Extension Points
Web API爲路由過程的某些部分提供了擴展點。
要爲以上任一接口提供本身的實現,可以使用HttpConfiguration對象的Services集合:
var config = GlobalConfiguration.Configuration; config.Services.Replace(typeof(IHttpControllerSelector), new MyControllerSelector(config));
總結
這一篇好難懂,無奈之下多查了一下,就感受確定早有人翻譯過了,還真是就在博客園就有,我以前咋就沒發現呢http://www.cnblogs.com/r01cn/archive/2012/12/04/2801158.html,感受大神翻譯的真心贊,好好看就看懂了,爲了提升本身閱讀英語的水平,看一句英文,看一句翻譯,而後本身再逐字敲一遍。這一篇下來真心累了。不過本身對Asp.Net MVC的路由機制也有了新的認識,不錯。
參考原文連接http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection