Asp.Net Web API(三)

來源:互聯網
上載者:User

標籤:技術   select   return   一個   script   匹配   獲得   bind   tor   

Routing Tables路由表

    在Asp.Net Web API中,一個控制器就是一個處理HTTP請求的類,控制器的public方法就被叫做action方法或簡單的Action。當Web API接收到一個請求的時候,它將這個請求路由到一個Action。

        注意:Web API的路由與Asp.Net MVC的路由是非常相似的。主要區別就是Web API使用的是HTTP方法,而不是URI路徑來選擇Action

   為了確定哪個Action被調用,這個架構使用了一個註冊表。Visual Studio的Web API的項目模板會建立一個預設路由:

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

這個路由是在WebApiConfig檔案中定義的,該檔案位於App_Start目錄

  當Web API架構接收到一個HTTP請求時,它會試圖根據路由表中的一個路由模板來匹配其URI。如果無路由匹配,用戶端會接收到一個404(未找到)錯誤。例如,以下URI與這個預設路由的匹配

  • /api/product
  • /api/product/1
  • /api/product?category=category

然而,以下URI就不匹配,因為它缺少“api”欄位

  • /product/1     

        注意:在路由中使用“api”的原因是為了避免與ASP.NET MVC的路由衝突。通過這種方式,可以用“/product”進入一個控制器,而“/api/product”進入一個Web API控制器。當然,如果你不喜歡這種約定,也可以修改這個預設路由表。

     一旦一個匹配的路由被發現,Web API便會選擇相應的Controller和Action。

         1.為了找到Controller,Web API會把“控制器”加到{Controller}變數的值

         2.為了找到Action,Web API會尋找HTTP方法,然後尋找一個名稱以HTTP方法名開頭的方法。例如:對於Get請求,Web API會尋找一個以“Get..”開頭的Action,這種約定只應用於GET,POST,PUT,DELETE方法,通過在Controller上使用attribute,你可以啟動其它的HTTP方法

         3.路由模板中其它的佔位變數;例如{id},將會被映射成Action的參數。

Routing Variations路由變化      HTTP方法

      替代使用HTTP方法的命名規範,你可以明確的為一個Action指定HTTP方法,通過以HttpGet,HttpPost,HttpPut或者HttpDelete屬性來對Action方法進行修身

      在下列樣本中,FindProduct方法被映射到GET請求

1 [HttpGet]2 public Product FindProduct(int id)3 {4    return repository.Get(id);5 }

使用上面代碼時需要先注釋上面寫的GetProduct(int id);

因為如果不注釋 Web API會匹配到請求匹配的多個操作錯誤

Web API允許一個Action對應多個HTTP方法;

 1 [AcceptVerbs("GET","POST","HEAD")] 2 public Product FindProduct(int id) 3 { 4     return repository.Get(id); 5 } 6 [AcceptVerbs("MKCOL")] 7 public void MakeCollection() 8 { 9 10 }

    第一個方法:指示該Action接收HTTP的GET,POST和HEAD方法。

    第二個方法:WebDAV方法,(基於Web的分布式著作與版本控制的HTTP方法,是一個擴充的HTTP方法,MKCOL時隸屬於WebDAV的一個方法,它在URI指定的位置建立集合)

通過Action名稱路由

   在預設的路由模板中,這個Web API使用HTTP方法去選擇Action。然而,你也可以在URI中建立包含Action名的路由

1 config.Routes.MapHttpRoute(2           name: "DefaultApi",3           routeTemplate: "api/{controller}/{Action}/{id}",4           defaults: new { id = RouteParameter.Optional }5 );

在這個路由模板中,{action}參數命名了控制器的Action方法。採用這種風格,需要使用註解屬性來指明所允許的HTTP方法。例如,假設你的控制器已有以下方法:

1 [HttpGet] 2 public string Details(int id); 

  在這中情況下,一個GET請求“api/Product/Details/1”將會映射到這個Detail方法。這種風格的路由類似於Asp.Net MVC,而且可能與RPC式的API接近。

  你也可以通過使用ActionName註解屬性來覆蓋動作名。在以下例子中,有兩個Action映射到"api/product/thumbnail/id"。一個支援GET,一個支援POST

1 [HttpGet]2 [ActionName("Thumbnail")]3 public HttpResponseMessage GetThumbnailImage(int id);4 [HttpPost]5 [ActionName("Thumbnail")]6 public void AddThumbnailImage(int id); 
NonActions

為了防止一個方法被當作Action所請求,可以使用NonAction註解屬性。它對架構發送訊號:這個方法不是以一個Action,即使它可能與路由規則匹配

1 [NonAction]2 public void IsNoAction();

Route Templates

   路由模板看起來類似一個URI路徑,但它可以具有預留位置,並用{}來指示:

"api/{controller}/public/{category}/{id}"

當建立一個路由的時候,你可以為某些或所有預留位置提供預設值

defaults: new { category = "all" }

你可以提供約束,它限制URI片段如何與預留位置匹配

constraints: new { id = @"\d+" }   // 只有在“id”是一個或多個數字時才匹配

  上面語句是通過Regex來限制片段的取值,上面的注釋說明id片段只匹配一個或多個數字,因此URI中id片段必須是一個數字才能與這個路由進行匹配。

 

  這個架構試圖把URI路徑中的片段與這個模板進行匹配。模板中文字必須嚴格匹配。一個預留位置可以匹配任何值,除非你指定了約束。這個架構不會URI另外的部分,例如主機名稱或者一個查詢字串。這個架構會選擇路由表中第一個匹配的路由。

   這個有兩個特殊的預留位置:“{Controller}”和“{Action}”。

       {Controller}提供控制器名

       {Action} 提供動作名。在Web API中,通常的約定是忽略{Action}的。

 

Defaults(預設值)

  如果你提供預設值,那麼這個路由匹配缺少這些片段的URI。例如

1 routes.MapHttpRoute(2     name: "DefaultApi", 3     routeTemplate: "api/{controller}/{category}", 4     defaults: new { category = "all" } 5 );

       這個URI“http://localhost/api/products”與這個路由是匹配的。“{category}”片段將賦成了預設值“all”。

 Route Dictionary(路由欄位)

     如果這個架構發現了一個匹配的URI,它會建立包含每個預留位置值的字典。這個索引值是不帶{}的預留位置名稱。這個值取自於URI路徑或是預設值。這個欄位被存在IHttpRouteData對象中。在匹配路由階段,這個特殊的{Controller}和{Action}預留位置的處理和其它預留位置是一樣的,它們用另外的值被簡單的儲存在字典中。

      在預設值中可以使用特殊的RouteParameter.Optional值。如果一個預留位置被賦予了這個值,那麼這個值將不會被添加到字典中,例如

1 routes.MapHttpRoute( 2     name: "DefaultApi", 3     routeTemplate: "api/{controller}/{category}/{id}", 4     defaults: new { category = "all", id = RouteParameter.Optional } 5 );

對於URI路徑“api/product”,路由字典將含有:controller:"product",category:"all"

然而,對於”api/product/toys/123“,路由字典將含有:controller:"product",category:"toys"

 

這個預設值也可以包含未出現的路由模板中的值。若這條路由匹配,則該值會被儲存在路由字典中。例如

1 routes.MapHttpRoute( 2     name: "Root", 3     routeTemplate: "api/root/{id}", 4     defaults: new { controller = "product", id = RouteParameter.Optional } 5 );

如果URI路徑是”api/root/7“,字典中將含有兩個值:controller:"product",id:"8"。

Selecting a Controller

     控制器選擇是由IHttpControllerSelector.SelectController方法來處理的。這個方法以HttpRequestMessage執行個體為參數。並返回HttpControllerDescriptor

     其預設實現是由DefaultHttpControllerSelector類提供的。這個類使用了一種很直接的演算法:

           1.尋找路由字典的”controller“鍵。

           2.取得這個鍵的值,並附加字串”Controller“,以得到控制器的類型名。

           3.用這個類型名尋找Web API控制器

     例如,如果路由字典的鍵-值對為”controller“=”product“,那麼控制器類型便為”ProductController“。如果沒有匹配,或多個匹配,Web API架構會給用戶端返回一個錯誤。

   對於步驟3,DefaultHttpControllerSelector使用IHttpControllerTypeResolver介面以獲得Web API控制類型的列表。IHttpControllerTypeResolver的預設實現會返回所有符合以下條件的public類:

  1.  實現IHttpController的類
  2. 是非抽象類別
  3. 名稱以”Contoller“結尾的類

Action Selection

      選擇了控制器後,Web API架構會通過調用IHttpActionSelector.SelectAction方法來選擇Action。這個方法以HttpControllerContext為參數,並返回HttpActionDescriptor。

      這個預設實現是由ApiControllerActionSelector類提供的。為了選擇一個Action,會尋找以下方面: 

  1. HTTP請求的方法
  2. 這個路由模板的action預留位置
  3. 控制器中Action的參數

      在尋找選擇演算法之前,我們需要理解控制器Action的一些事情

          控制器的哪些方法被看成為Action?當選擇一個Action時,這個架構只考察控制器的public執行個體方法。而且,它會排除特殊名稱的方法(構造器,事件,操作符,重載符等),以及整合自ApiController的類方法

HTTP Methods

    Web API架構只會選擇與請求的HTTP方法匹配的Action,確定如下

  1. 你可以用註解屬性AcceptVerbs,HttpDelete,HttpGet,HttpPost,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。對於每一個Action,最多隻有一個參數可以讀取請求本文。

   在這種背景下,Action選擇演算法如下

  1. 建立該控制器中與HTTP要求方法匹配的所有Action的列表
  2. 如果路由字典有Action條目,移除與該條目值不匹配的Action
  3. 試圖將Action參數與該URI匹配,如下       

              a:針對每個Action,獲得簡單類型的參數列表,這是綁定得到URI參數的地方。該列表不包括選擇性參數

              b:從這個列表中,試著在路由字典或是在URI查詢字串中,找到每個參數的匹配。匹配是與大小寫無關的,且與參數順序無關

              c:選擇這樣的一個Action,在列表中的每個參數在URI中有一個匹配

              d:如果滿足這些條件的Action不止一個,選用參數匹配最多的一個。

         4.忽略用[NonAction]註解屬性標註的Action。

    第3步可能會rang人困擾。其基本思想是,可以從URI,或請求體,或一個自訂綁定來擷取參數值。對於來自URI的參數,我們希望確保URI在其路徑(通過路由字典)或查詢字串中實際包含一個用於此參數的值。

   例如,考慮以下Action

public void Get(int id)

   其id綁定到URI。因此,這個Action只能匹配在路由字典或查詢字串包含了id值的URI

   選擇性參數是一個例外,因為它們是可選的。對於選擇性參數,如果綁定不能通過URI擷取它的值,是沒關係的。

   複雜類型是另一個原因的例外。一個複雜類型只能通過自訂綁定來綁定到URI。但是在這種情況下,Web API架構不能提前知道是否這個參數被綁定到一個特殊的URI。為了查明情況,這個架構需要調用這個綁定。選擇演算法的目的是在調用綁定之前根據靜態描述來選擇一個Action。因此,負責類型是屬於匹配演算法之外的。

    Action選擇之後,會調用所有參數綁定。

Summary:

  1.  Action必須匹配請求的HTTP方法。
  2. Action名必須匹配路由字典中的Action條目,如果有的話。
  3. 對於Action的各個參數,如果參數來自URI,那麼該參數名必須在路由字典或URI查詢字串中能夠被找到(選擇性參數和複雜參數類型除外)
  4. 試圖匹配最多數目的參數。首選可能是一個無參數的方法。

Extended Points

        Web API為路由過程的某些部分提供了擴充點。

要為以上任一介面提供自己的實現,可使用HttpConfiguration對象的Services集合:

var config = GlobalConfiguration.Configuration;config.Services.Replace(typeof(IHttpControllerSelector), new MyControllerSelector(config));

 

         

Asp.Net Web API(三)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.