Web Api 2(三)之路由與Action的選擇


路由(Route

  Web Api中的路由與Asp.net mvc中的路由基本上一樣,一個路由看起來像是一個URI路徑,但是路由中包含一些大括號包括的占位符(place holder),例如:
  
  api/{Controller}/{Action}/{Id}

  當你創建一個路由的時候,你可以為一個或多個占位符設置默認值,例如下面的例子將Controller設為Account,如果請求訪問的URL沒有提供Controller時,將會使用設置的默認的 Controller
  
  defaults:new {Controller=Account}

   你還可以為占位符設置一些限制,下面的例子限制Id只能為數字

  constraints:new{ id = @"\d+"}


  Web Api中的路由主要有三個主要的功能:

  - 將請求的URI與路由模板進行匹配
  - 選擇Controller
  - 選擇Action
  
  當收到請求是,Web Api會嘗試着將請求URI與路由表(Route Table)中注冊的路由模板進行比對,模板中的字面值(Literals)必須被准確的匹配,如上面例子中的api片段,請求的URL必須包含api才能匹配上面的路由,而占位符可以匹配任何值(除非你有其它特殊的限制),將請求的URL進行匹配時,只會比對路由模板中有的片段(Segment),而路由模板中沒有的則不會比對,如主機名(host name)、查詢參數(query parameters)等,之后選擇路由表中匹配的第一個路由來進行下一步的處理
  
  Web Api提供的默認路由如下:

	 config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

  default中設置的id = RouteParameter.Optional表示路由模板中id是不是必須的,而是可選的,只有在請求的URL存在時才會被賦值


路由字典(Route Dictionary

如果請求的URL匹配到了與之匹配的路由時,Web api會創建一個Dictionary來存放URL中與路由模板中占位符對應的字段值,這個Dictionary的Key就是路由模板的占位符的名稱(不包括大括號),這些值即可能來自URL,也可能來自注冊路由時設置的默認值。而這個Dictionary就存放IHttpRouteData類型的對象中。


注意 : 如果路由中的占位符被設置為 RouteParameter.Optional,那么這個參數的值(即RouteParameter.Optional)不會被加入到上述的Dictionary中。但如果這個占位符被分配了具體的值的話,這個Dictionary中還是會存儲這個值的,例如:api/products,那么此時這個Dictionary中存儲的就是:

  • controller: "products"
  • category:"all"

  並不會存儲: id:RouteParameter.Optional,在比如,api/products/toys/123,那么此時這個Dictionary中存儲的就是:

  • controller:"products"
  • catagory: "toys"
  • id : "123"

  這個字典中甚至可以包含路由模板中不存在,但在默認值中存在的值,例如:

	routes.MapHttpRoute(
		name:"Root",
		routeTemplate:"api/root/{id}",
		default:new { controller="customers",id = RouteParameter.Optional}
	)

  如果URL中分離出的片段為api/root/8,那么此時這個Dictionary中存儲的是:

  • controller:"customers
  • id : "8"


> #### Controller的選擇

  Controller的選擇是通過IHttpControllerSelector.SelectController 的方法來實現的,這個方法接收一個** HttpRequestMessage類型對象返回一個 HttpControllerDescriptor **,默認使用的是Web api內部提供的 DefaultHttpControllerSelector,這個類使用下面的邏輯來選擇Controller:

  1. "Controller"為Key到上述的Dictionary(存儲在IHttpRouteData類型中)查找對應的Value
  2. 在獲取到的值(即請求的Controller名稱)后面附加"Controller"字符串去獲取對應的Controller的類型名稱
  3. 拿第二步得到的Controller的名稱去獲取對應的Web Api Controller對象(ApiController類型)

  例如,如果路由字典(Route Dictionary)包含鍵值對(key-value pair)"Controller=products",那么控制器的類型便是"ProductsController",如果沒有找到與之匹配的ApiController類型或者有多個匹配,則返回一個錯誤給請求的客戶端。

  在第三步中,DefaultHttpControllerSelector 使用 IHttpControllerTypeResolver(典型的IOC應用)接口去獲取所有的ApiController類型(均派生在ApiController),這個接口返回滿足一下條件的所有公共(Public)類型:

  • 實現IHttpController接口
  • 非抽象類
  • 類名以"Controller"結束

> #### Action的選擇

  在得到匹配的Controller類型后,Web Api會調用IHttpActionSelector.SelectAction方法去選擇Action,這個方法接收一個HttpControllerContext類型參數,返回一個HttpActionSelector類型實例。選擇Action的大致過程如下:

  1. 查看請求的Http Method(Get、POST等),獲取請求的Action名稱,方法和獲取Controller名稱的方法一致,以"Action"為Key到路由字典中獲取對應值
  2. 查看路由表中注冊的路由模板中的默認值
  3. 查看Controller中定義的Action方法的參數,找出參數最匹配的一個Action

  那么,滿足什么條件的方法才能被視為一個Action呢?滿足如下條件的方法便會被認為是Action

  • 定義在Controller中的所有公共的實例方法(不包括一些具有特殊名稱的方法,如構造函數、事件、運算符重載等)

  Web Api僅僅選擇那些與請求的Http Method匹配的Action:

  • 一個Action如果沒有特殊說明,那么它的Http Method為POST
  • 你可以通過[HttpGet]、[HttpPost]、[HttpDelete]、[HttpHead]、[HttpOptions]、[HttpPatch]、[HttpPut] 特性來顯式的聲明一個Action的支持的Http Method,也可以通過HttpVerbs特性來聲明。
  • 如果一個Action的名稱以PostGet、Patch、Head、Put、Options、Delete等字符開頭的,則認為該Action支持對應的Http Method。

Action 的參數綁定

  Web Api中,Action的參數的創建過程稱為參數的綁定,遵照一下的規則:

  • 簡單類型(Simple Type)的參數從URI中獲取其參數值
  • 復雜類型(Complex Type)的參數從Http的請求報文中獲取其參數值

  那么如何區分簡單類型和復雜類型呢?在Web Api中,如果一個數據類型支持源自字符串的類型轉換,那么該數據對象就是簡單類型,否則,該數據對象就是復雜類型,按照這個判斷的標准,Net中的所有的基元類型(Primative Type)和可空值類型(Nullable Type)、外加 DateTime, Decimal, Guid, String, and TimeSpan.都是簡單類型,而一個自定義的類型默認情況下都是復雜類型.對於一個Action來說,之多有一個參數來自於Http請求報文

注: 在C#中,能夠直接被編譯器識別的類型稱為基元類型.如int、byte等,其分別對應着FCL中的System.Int32System.Byte



  了解了上面的東西后,我們看一下Action 選擇的機制(簡單參數類型)

  1. 將 Controller中所有滿足請求Http Method的Action放入一個列表中
  2. 如果路由字典中存在"Action"條目,則從創建好的Action列表中移除名稱不匹配的Action.
  3. 嘗試着通過URI去獲取Action的參數
  • 對於每個Action,獲取其簡單參數類型的參數列表,這其中不包括可選參數(Optional Parameters
  • 試着根據參數名稱從參數列表、路由字典(Route Dictionary)或查詢字符串(Query String)中獲取對應的參數值,這個匹配過程參數名稱不區分大小寫,也不依賴於參數的順序。
  • 選擇一個Action,其參數列表中的每個參數在URI都有與之對應的參數值
  • 如果有多個Action滿足條件,則選擇一個最為匹配的一個
  1. 忽略那些應用了[NonAction]特性的Action

> #### 其它

  Web Api的路由過程是支持擴展的,當內置的實現邏輯不足以滿足應用的需求時,此時,便可以通過實現相應的接口來對邏輯進行自定義。其中相關的接口及其作用如下:

接口 描述
IHttpControllerSelector 選擇控制器
IHttpControllerResolver 獲取控制器類型列表,默認的DefaultHttpControllerSelector
獲取的控制器類型列表中選擇控制器
IAssemblyResolver 獲取項目的程序集列表,IHttpControllerTypeResolver使用這個列表去查找控制器類型
IHttpControllerActivator 創建控制器實例
IHttpActionSelector 選擇Action
IHttpActionInvoker 執行Action

  在實現某個接口后,然后使用*HttpConfiguration*類的*Service*集合去注冊后,Web Api便會使用自定義的邏輯去替換掉內置的默認實現。 ```C# var config = GlobalConfiguration.Configuration; config.Services.Replace(typeof(IHttpControllerSelector),new MyControllerSelector(config)); ```


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM