在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ C#/ 這篇文章描述了ASP.NET Web API如何將HTTP請求路由到控制器上的特定動作。
前言
在本節(jié),你將開始為app定義HTML,并在HTML和視圖模型間添加數(shù)據(jù)綁定。
在本節(jié),你將使用HTML、JavaScript和Knockout.js庫為應用程序創(chuàng)建客戶端。我們將按如下步驟建立客戶端應用:
前言
前言
http://www.asp.net/web-api/overview/formats-and-model-binding/mo
在本節(jié),你將添加讓用戶可以創(chuàng)建新book的功能。在app.js中,添加如下代碼到視圖模型:
在本節(jié),你將添加查看每本書的詳細信息的功能。在app.js中,添加以下代碼到視圖模型:
前言
這篇文章描述了ASP.NET Web API如何將HTTP請求發(fā)送(路由)到控制器。
前言
前言
這篇文章描述了ASP.NET Web API如何將HTTP請求路由到控制器上的特定動作。
前言
在這最后一節(jié)中,你將把應用程序發(fā)布到Azure。在Solution Explorer中,右擊項目并選擇Publish。
前言
總結

這篇文章描述了ASP.NET Web API如何將HTTP請求路由到控制器上的特定動作。

這篇文章描述了ASP.NET Web API如何將HTTP請求路由到控制器上的特定動作。

備注:想要了解關于路由的高層次概述,請查看Routing in ASP.NET Web API。

這篇文章側重于路由過程的細節(jié)。如果你創(chuàng)建了一個Web API項目并且發(fā)現(xiàn)一些請求并沒有按你預期得到相應的路由,希望這篇文章有所幫助。

路由有以下三個主要階段:

  1. 將URI匹配到路由模板
  2. 選擇一個控制器
  3. 選擇一個動作

你可以用自己的習慣行為來替換其中一些過程。在本文中,我會描述默認行為。在結尾,我會指出你可以自定義行為的地方。

路由模板(Route Templates)

路由模板看起來和URI路徑非常相似,但是它能包含用大括號指明的占位符。

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

當你創(chuàng)建了一個路由,你為一些或全部占位符提供默認的值:

defaults: new { category = "all" }

你也可以提供一些約束(constraints),它限制了URI字段如何才能匹配一個占位符:

constraints: new { id = @"\d+" }   // Only matches if "id" is one or more digits.

框架會盡力將URI路徑中的字段匹配到模板中。模板中的文字必須準確匹配。一個占位符可以匹配多個變量,除非你指定了約束??蚣懿粫ヅ銾RI的其他部分,比如主機名或查詢參數(shù)。框架僅僅在用于匹配URI的路由表中選擇第一個路由。

這里有兩個特殊的占位符:”{controller}“和“{action}”。

  • “{controller}“提供了控制器的名稱。
  • “{action}“提供了動作的名稱。在Web API中,通過會忽略“{action}”。

Defaults

如果你提供了默認的API,路由將會匹配缺少這些的URI。例如:

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

對于URI http: //localhost/api/products 將會匹配這個路由。{category} 字段會被分配默認值 all

路由字典(Route Dictionary)

如果框架發(fā)現(xiàn)了URI的一個匹配,它會創(chuàng)建一個包含了每個占位符適用的值的字典集合。鍵是不包含大括號的占位符名稱。值是提取自URI路徑或者默認表單。該字典被存儲在IHttpRouteData對象中。

在路由匹配階段,“{controller}“和”{action}“占位符會被像其他占位符一樣對待。它們被同其他值一起簡單地存儲在字典中。

對于defaults,它可以有一個特殊值RouteParameter.Optional。如果一個占位符被分配到這個值,那么這個值不會被添加到路由字典中。例如:

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

對于URI路徑“api/products”,路由字典將會包含:

  1. controller:“products”
  2. category:“all”

然而對于“api/products/toys/123”,路由字典將會包含:

  1. controller:“products”
  2. category:“all”
  3. id:“123“

對于defaults,它同樣也會包含一個沒有在路由模板中任何地方出現(xiàn)的值。如果路由匹配了,這個值會被存儲在字典中。例如:

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對象。默認的實現(xiàn)是由DefaultHttpControllerSelector類來實現(xiàn)的。這個類使用了一個簡單的算法:

  1. 在路由字典中查找鍵”controller“。
  2. 提取出這個鍵對應的值,并添加字符串“Controller”以得到控制器的類型名
  3. 用這個類型名來查找一個Web API控制器

例如,如果路由字典包含鍵值對“controller”=“products”,那么控制器類型就是“ProductsController”。如果這里不存在匹配的類型,或存在多個匹配,那么框架就會向客戶端發(fā)送一個錯誤。

對于步驟3,DefaultHttpControllerSelector會使用IHttpControllerTypeResolver接口來得到Web API控制器類型的列表。IHttpControllerTypeResolver的默認實現(xiàn)會返回(a)實現(xiàn)IHttpController,(b)不是抽象的,(c)名稱以“Controller“結尾的所有公共的類。

動作選擇

在選擇控制器之后,框架會通過調用IHttpActionSelector.SelectAction方法來選擇動作。這個方法需要傳入一個HttpControllerContext參數(shù)以及返回一個HttpActionDescriptor對象。

默認的實現(xiàn)由ApiControllerActionSelector類來提供。為了選擇一個動作,它會按以下要求來查找: 1) 請求的HTTP方法 2) 路由模板中的“{action}“占位符(如果存在) 3) 控制器中動作的參數(shù)

在查看選擇算法之前,我們需要理解關于控制器動作的一些東西。

控制器中的哪些方法會被認為是“動作“?當選擇一個動作時,框架僅僅在控制器中查找公共的實例方法。當然了,它會排除一些”特殊“的方法(構造函數(shù),事件,操作重載等等)和繼承自ApiController類的方法。

HTTP方法。框架只會選擇匹配請求的HTTP方法的動作,它取決于以下幾點:

  1. 你可以用某個屬性來具體說明是HTTP方法:AcceptVerbs,HttpDelete,HttpGet,HttpHead,HttpOptions,HttpPatch,HttpPost或HttpPut。
  2. 或者,如果一個控制器方法的名稱以”Get”,“Post“,”Put“,”Delete“,”Head“,”O(jiān)ptions“或”Patch“開始,那么按照約定該動作就支持HTTP方法。
  3. 如果不包含以上幾點,但支持POST的方法。

參數(shù)綁定。參數(shù)綁定是指Web API如何如何為參數(shù)創(chuàng)建一個值。這里是參數(shù)綁定的默認規(guī)則:

  1. 簡單類型直接從URI中提取
  2. 復雜類型從請求體重提取

簡單類型包括所有.NET框架基本類型(.NET Framework primitive types),再加上DateTime、Decimal、Guid、String和TimeSpan。對于每個動作,最多有一個參數(shù)可以讀取請求體。

備注:重載默認綁定規(guī)則也是有可能的。查看WebAPI Parameter binding under the hood.

有了以上這些背景知識,這里是動作選擇的算法:

  1. 基于HTTP請求方法匹配到的控制器創(chuàng)建一個動作列表。
  2. 動作路由字典包含“action“記錄,移除其名字不匹配該值的動作。
  3. 根據(jù)如下規(guī)則,盡力將動作參數(shù)匹配到URI:
  • a 對于每個動作,當綁定從URI中獲得參數(shù)時得到一個簡單類型的參數(shù)列表。執(zhí)行可選的參數(shù)。
  • b 從這個列表中,無論是在路由字典中還是URI查詢字符串中,都盡力找出針對每個參數(shù)名稱的匹配。匹配不區(qū)分大小寫并且不取決于參數(shù)順序。
  • c 當列表中的每個參數(shù)在URI中都有一個匹配時,選擇一個動作。
  • d 如果多個動作符合這些標準,那么選擇其中一個有最多參數(shù)匹配的。
  1. 忽略包含[NonAction]屬性的動作。

步驟3可能是最容易迷惑的?;镜乃枷胧菂?shù)可以從URI、請求體或綁定中獲得它的值。對于來自URI的參數(shù),我們會確保URI確實包含一個給參數(shù)的值,不論是在路徑(通過路由字典)還是在查詢字符串中。

例如,考慮如下動作:

public void Get(int id)

這個id參數(shù)綁定到URI上,因此,這個動作可以匹配到包含一個給“id“的值的URI,不論是在路由字典還是查詢字符串中。

可選參數(shù)是個例外,因為它們是可選的。對于可選參數(shù),如果這個綁定不了從URI中得到這個值也是沒關系的。

因為一些不同的原因,復雜類型也是個例外。復雜類型只能通過自定義綁定來綁定到URI上。但是在這種情況下,框架無法事先知道參數(shù)可能被綁定到一個特殊的URI。為了弄清楚它,就需要去執(zhí)行這個綁定。這個選擇算法的目標是在執(zhí)行任何綁定之前,從靜態(tài)描述中去選擇一個動作。因此,復雜類型會從這種匹配算法中執(zhí)行。

在動作被選取好了,所有的參數(shù)綁定也就被執(zhí)行了。

總結:

  1. 動作必須匹配請求的HTTP方法。
  2. 動作名(如果存在)必須匹配路由字典中的“action“詞條
  3. 對于動作的所有參數(shù),如果參數(shù)提取自URI,那么參數(shù)名必須在路由字典或URI查詢字符串中被找到。(可選參數(shù)和復雜類型的參數(shù)除外。)
  4. 盡量去匹配最多的參數(shù)數(shù)目。但最好的匹配也可能是不包含任何參數(shù)的方法。

擴展示例(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 }
);

控制器:

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請求:

GET http://localhost:34701/api/products/1?version=1.5&details=1

路由匹配(Route Matching)

該URI會匹配到名為”DefaultApi”的路由。這個路由字典包含以下詞條:

  • controller:“products”
  • id:“1“

這個路由字典不包含查詢字符串“version”和“details”,但是在動作選擇的時候這些仍然會被考慮。

控制器選擇(Controller Selection)

根據(jù)路由字典中的“controller”詞條,控制器類型是ProductsController。

動作選擇(Action Selection)

該HTTP請求是一個GET請求。相應的支持GET的控制器動作是GetAll、GetById和FindProductsByName。路由字典中不包含任何“action“詞條,所以我們不用去匹配動作名稱。

接下來,我們嘗試著匹配動作的參數(shù)名稱,現(xiàn)在僅在GET動作中查找。

Action Parameters to Match
GetAll none
GetById "id"
FindProductsByName "name"

注意到GetById的version參數(shù)沒有被考慮,因為它是一個可選參數(shù)。

顯而易見GetAll方法能夠匹配,GetById方法也能匹配,因為路由字典中包含“id“。FindProductsByName方法不匹配。

最后是GetById方法獲勝,因為它能夠匹配到一個參數(shù),相對應的是沒有參數(shù)能匹配GetAll。該方法伴隨以下參數(shù)的值來執(zhí)行:

  • id = 1
  • version = 1.5

注意到盡管version參數(shù)沒有在選擇算法中使用,但該參數(shù)的值也依舊是來自URI的查詢字符串中。

擴展點(Extension Points)

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

Interface Description
IHttpControllerSelector Selects the controller.
IHttpControllerTypeResolver Gets the list of controller types. The DefaultHttpControllerSelector chooses the controller type from this list.
IAssembliesResolver Gets the list of project assemblies. The IHttpControllerTypeResolverinterface uses this list to find the controller types.
IHttpControllerActivator Creates new controller instances.
IHttpActionSelector Selects the action.
IHttpActionInvoker Invokes the action.

為任何這些接口提供自己的實現(xiàn),請使用HttpConfiguration對象上的Services集合:

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