天天看點

【Web API系列教程】2.1 — ASP.NET Web API中的路由機制

這篇文章描述了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會比對到預設路由:

  1. /api/contacts
  2. /api/contacts/1
  3. /api/products/gizmo1

然而,以下URI不會比對到,因為它缺乏“api”字段。

/contacts/1           

備注:在路由中使用“api”的原因是為了避免和ASP.NET MVC的路由沖突。也就是說,你可以使用”/contacts”比對到MVC的路由,使用“api/contacts”比對到Web API的路由。當然了,如果你不喜歡這種約定,你也可以修改預設路由表。

一旦某個路由比對到了,Web API就會選擇相應的控制器及動作:

  1. 為了找到控制器,Web API将“Controller”添加到{controller}變量上。
  2. 為了找到動作,Web API會周遊HTTP方法,然後查找一個其名字以HTTP方法的名字開頭的動作。例如,有一個GET請求,Web API會查找以“Get….”開頭的動作,比如”GetContact”或”GetAllContacts”。這種方式僅僅适用于GET、POST、PUT和DELETE方法。你可以通過在你的控制器中使用屬性來啟用其他HTTP方法。将晚些看到一個示例(超連結到本章的第三節……
  3. 路由模闆的其他占位符變量,比如{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() { ... }
           

繼續閱讀