這篇文章描述了ASP.NET Web API如何将HTTP請求發送(路由)到控制器。
備注:如果你對ASP.NET MVC很熟悉,你會發現Web API路由和MVC路由非常相似。主要差別是Web API使用HTTP方法來選擇動作(action),而不是URI路徑。你也可以在Web API中使用MVC風格的路由。這篇文章不需要ASP.NET MVC的任何知識。
路由表
在ASP.NET Web API中,控制器是一個用于處理HTTP請求的類。控制器中的公共方法被稱為動作方法或簡單動作。當Web API架構收到請求時,它會将該請求路由到相應的動作中。
為了确定哪個動作該被執行,架構就會使用本節将講解的路由表。Visual Studio的Web API項目模闆就建立了一個預設的路由表:
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
這個路由被定義在App_Start目錄下的WepApiConfig.cs檔案中。
路由表中的每條記錄都包含了一個路由模闆。Web API的預設路由模闆是“api/{controller}/{id}”。在這個模闆中,”api”是一個字面路徑字段,而{controller}和{id}都是占位符變量。
當Web API架構收到了HTTP請求時,它将會盡力比對URI到路由表中的路由模闆的其中一個。如果沒有路由被比對到,用戶端就會收到404錯誤。例如,以下URI會比對到預設路由:
- /api/contacts
- /api/contacts/1
- /api/products/gizmo1
然而,以下URI不會比對到,因為它缺乏“api”字段。
/contacts/1
備注:在路由中使用“api”的原因是為了避免和ASP.NET MVC的路由沖突。也就是說,你可以使用”/contacts”比對到MVC的路由,使用“api/contacts”比對到Web API的路由。當然了,如果你不喜歡這種約定,你也可以修改預設路由表。
一旦某個路由比對到了,Web API就會選擇相應的控制器及動作:
- 為了找到控制器,Web API将“Controller”添加到{controller}變量上。
- 為了找到動作,Web API會周遊HTTP方法,然後查找一個其名字以HTTP方法的名字開頭的動作。例如,有一個GET請求,Web API會查找以“Get….”開頭的動作,比如”GetContact”或”GetAllContacts”。這種方式僅僅适用于GET、POST、PUT和DELETE方法。你可以通過在你的控制器中使用屬性來啟用其他HTTP方法。将晚些看到一個示例(超連結到本章的第三節……
- 路由模闆的其他占位符變量,比如{id},會被映射到動作的參數。
讓我們來看一個示例。假定你定義了如下的控制器:
public class ProductsController : ApiController
{
public void GetAllProducts() { }
public IEnumerable<Product> GetProductById(int id) { }
public HttpResponseMessage DeleteProduct(int id){ }
}
這裡是一些可能的HTTP請求,以及相應的得到執行的動作:
HTTP Method | URI Path | Action | Parameter |
---|---|---|---|
GET | api/products | GetAllProducts | (none) |
api/products/4 | GetProductById | 4 | |
DELETE | DeleteProduct | ||
POST | (no match) |
注意URI的{id}字段,如果存在,它會被映射到動作的id參數中。在本例,控制器定義了兩個GET方法,其中一個包含id參數,而另一個不包含id參數。
同樣的,注意到POST請求會失敗,因為控制器中并沒有定義”POST…”方法。
路由偏差(Routing Variations)
前一節描述了ASP.NET Web API的基本路由機制。本節将開始描述一些變化。
HTTP方法
除了使用這些HTTP方法的命名約定,你也可以通過用HttpGet、HttpPut、HttpPost或HttpDelete屬性來賦予這些動作來具體地為每個動作設定HTTP方法。
在下面這個例子中,FindProduct方法被映射到GET請求:
public class ProductsController : ApiController
{
[HttpGet]
public Product FindProduct(id) {}
}
為了讓一個動作支援多個HTTP方法,或支援除GET、PUT、POST和DELETE之外的HTTP方法,你可以使用AcceptVerbs屬性,它以一個HTTP方法清單為參數。
public class ProductsController : ApiController
{
[AcceptVerbs("GET", "HEAD")]
public Product FindProduct(id) { }
// WebDAV method
[AcceptVerbs("MKCOL")]
public void MakeCollection() { }
}
通過動作名進行路由
有了預設的路由模闆,Web API使用HTTP方法來選擇動作。然而,你也可以建立一個将動作名包含在URI中的路由表。
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
在這個路由模闆中,{action}參數在控制器中命名了一個動作方法。在這種風格的路由中,應使用屬性來指定允許的HTTP方法。例如,假定你的控制器有了以下方法:
public class ProductsController : ApiController
{
[HttpGet]
public string Details(int id);
}
在這種情況下,對于“api/products/details/1”的GET請求被被映射到Details方法。這種風格的路由和ASP.NET MVC很接近,并且可能适合于RPC風格的API。
你可以通過ActionName屬性來重寫動作名。在接下來的例子中,存在兩個都映射到”api/products/thumbnail/id”的動作。其中一個支援GET,另一個支援POST:
public class ProductsController : ApiController
{
[HttpGet]
[ActionName("Thumbnail")]
public HttpResponseMessage GetThumbnailImage(int id);
[HttpPost]
[ActionName("Thumbnail")]
public void AddThumbnailImage(int id);
}
無動作(Non-Actions)
為了阻止一個方法被當作動作來執行,可以使用NonAction屬性。這會架構指明該方法并非一個動作,即使是它可能比對到路由規則。
// Not an action method.
[NonAction]
public string GetPrivateData() { ... }