這篇文章描述了ASP.NET Web API如何將HTTP請求發(fā)送(路由)到控制器。
備注:如果你對ASP.NET MVC很熟悉,你會發(fā)現(xiàn)Web API路由和MVC路由非常相似。主要區(qū)別是Web API使用HTTP方法來選擇動作(action),而不是URI路徑。你也可以在Web API中使用MVC風(fēng)格的路由。這篇文章不需要ASP.NET MVC的任何知識。
在ASP.NET Web API中,控制器是一個(gè)用于處理HTTP請求的類??刂破髦械墓卜椒ū环Q為動作方法或簡單動作。當(dāng)Web API框架收到請求時(shí),它會將該請求路由到相應(yīng)的動作中。
為了確定哪個(gè)動作該被執(zhí)行,框架就會使用本節(jié)將講解的路由表。Visual Studio的Web API項(xiàng)目模板就創(chuàng)建了一個(gè)默認(rèn)的路由表:
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
這個(gè)路由被定義在App_Start目錄下的WepApiConfig.cs文件中。
路由表中的每條記錄都包含了一個(gè)路由模板。Web API的默認(rèn)路由模板是“api/{controller}/{id}”。在這個(gè)模板中,”api”是一個(gè)字面路徑字段,而{controller}和{id}都是占位符變量。
當(dāng)Web API框架收到了HTTP請求時(shí),它將會盡力匹配URI到路由表中的路由模板的其中一個(gè)。如果沒有路由被匹配到,客戶端就會收到404錯(cuò)誤。例如,以下URI會匹配到默認(rèn)路由:
然而,以下URI不會匹配到,因?yàn)樗狈Α癮pi”字段。
/contacts/1
備注:在路由中使用“api”的原因是為了避免和ASP.NET MVC的路由沖突。也就是說,你可以使用”/contacts”匹配到MVC的路由,使用“api/contacts”匹配到Web API的路由。當(dāng)然了,如果你不喜歡這種約定,你也可以修改默認(rèn)路由表。
一旦某個(gè)路由匹配到了,Web API就會選擇相應(yīng)的控制器及動作:
讓我們來看一個(gè)示例。假定你定義了如下的控制器:
public class ProductsController : ApiController
{
public void GetAllProducts() { }
public IEnumerable<Product> GetProductById(int id) { }
public HttpResponseMessage DeleteProduct(int id){ }
}
這里是一些可能的HTTP請求,以及相應(yīng)的得到執(zhí)行的動作:
| HTTP Method | URI Path | Action | Parameter |
|---|---|---|---|
| GET | api/products | GetAllProducts | (none) |
| GET | api/products/4 | GetProductById | 4 |
| DELETE | api/products/4 | DeleteProduct | 4 |
| POST | api/products | (no match) |
注意URI的{id}字段,如果存在,它會被映射到動作的id參數(shù)中。在本例,控制器定義了兩個(gè)GET方法,其中一個(gè)包含id參數(shù),而另一個(gè)不包含id參數(shù)。
同樣的,注意到POST請求會失敗,因?yàn)榭刂破髦胁]有定義”POST...”方法。
前一節(jié)描述了ASP.NET Web API的基本路由機(jī)制。本節(jié)將開始描述一些變化。
HTTP方法
除了使用這些HTTP方法的命名約定,你也可以通過用HttpGet、HttpPut、HttpPost或HttpDelete屬性來賦予這些動作來具體地為每個(gè)動作設(shè)定HTTP方法。
在下面這個(gè)例子中,F(xiàn)indProduct方法被映射到GET請求:
public class ProductsController : ApiController
{
[HttpGet]
public Product FindProduct(id) {}
}
為了讓一個(gè)動作支持多個(gè)HTTP方法,或支持除GET、PUT、POST和DELETE之外的HTTP方法,你可以使用AcceptVerbs屬性,它以一個(gè)HTTP方法列表為參數(shù)。
public class ProductsController : ApiController
{
[AcceptVerbs("GET", "HEAD")]
public Product FindProduct(id) { }
// WebDAV method
[AcceptVerbs("MKCOL")]
public void MakeCollection() { }
}
有了默認(rèn)的路由模板,Web API使用HTTP方法來選擇動作。然而,你也可以創(chuàng)建一個(gè)將動作名包含在URI中的路由表。
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
在這個(gè)路由模板中,{action}參數(shù)在控制器中命名了一個(gè)動作方法。在這種風(fēng)格的路由中,應(yīng)使用屬性來指定允許的HTTP方法。例如,假定你的控制器有了以下方法:
public class ProductsController : ApiController
{
[HttpGet]
public string Details(int id);
}
在這種情況下,對于“api/products/details/1”的GET請求被被映射到Details方法。這種風(fēng)格的路由和ASP.NET MVC很接近,并且可能適合于RPC風(fēng)格的API。
你可以通過ActionName屬性來重寫動作名。在接下來的例子中,存在兩個(gè)都映射到”api/products/thumbnail/id”的動作。其中一個(gè)支持GET,另一個(gè)支持POST:
public class ProductsController : ApiController
{
[HttpGet]
[ActionName("Thumbnail")]
public HttpResponseMessage GetThumbnailImage(int id);
[HttpPost]
[ActionName("Thumbnail")]
public void AddThumbnailImage(int id);
}
為了阻止一個(gè)方法被當(dāng)作動作來執(zhí)行,可以使用NonAction屬性。這會框架指明該方法并非一個(gè)動作,即使是它可能匹配到路由規(guī)則。
// Not an action method.
[NonAction]
public string GetPrivateData() { ... }