【翻译】ASP.NET MVC Web API 的路由选择

这是本人翻译的第一篇英文文章,翻译的还非常不好,大家见谅

原文链接:http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

此文章描述了ASP.NET Web API如何将Http请求路由到controller。

路由表

在ASP.NET Web API中,controller是用来处理HTTP请求的一个类。这个类中用于处理HTTP请求的的公共方法被称之为action method或者简称action。当Web API框架接收到一个请求时,会将这个请求路由到一个action来处理。

ASP.NET Web API框架通过使用路由表来确定哪个action方法被调用。Visual Studio 中的ASP.NET Web API项目模板会创建一个默认的路由:

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

这个默认路由被定义在App_Start目录下的WebApiConfig.cs文件中。

关于WebApiConfig类的更多信息,参见Configuring ASP.NET Web API.

路由表中的每一条记录都包含了一个路由模板。默认的Web API路由模板是"api/{controller}/{id}"。在这个模板中,"api"是固定的值,而{controller}和{id}则仅仅是占位符而已(类似于string.Format方法中的格式化字符串使用{0}占位)。

当Web API框架接收到一个HTTP请求时,它会尝试使用路由表中的路由模板来匹配请求的URI。如果没有匹配的模板,客户端就会接收到一个404错误。如下的几个URI是匹配默认模板的:

  • /api/contacts
  • /api/contacts/1
  • /api/products/gizmo1

但是下面的这个URI是不匹配的,因为它缺少"api"部分

/contacts/1

注意:之所以在路由模板中使用"api"这个固定量是为了避免与ASP.NET MVC路由冲突。在ASP.NET MVC中,你可以使用"/contacts"来匹配一个普通的controller,而使用"/api/contacts"来匹配Web API的controller。当然,如果你不喜欢这种约定,也可以更改默认的路由表。

一旦发现了匹配的路由模板,Web API就会选择合适的controller和action:

1.选择controller,Web API会在匹配{controller}占位符的值后面加上"Controller",来查找同名的controller

2.选择action,Web API会查找以HTTP请求的method开头的方法。比如,有一个Get请求,那么Web API就会查找controller中以Get开头的方法,比如"GetContact"或者"GetAllContacts".这种约定仅适用于GET,POST,PUT和DELETE方法,你可以通过在方法上面添加特性来启用某种HTTP method,我们会在后面展示这个例子。

3.路由模板里的其它占位符,比如{id},会被映射到action的参数列表。

 

我们先来看一个例子,假设有如下定义的一个controller

public class ProductsController : ApiController
{
    public void GetAllProducts() { }
    public IEnumerable<Product> GetProductById(int id) { }
    public HttpResponseMessage DeleteProduct(int id){ }
}

下面是一些可能的HTTP请求和会被调用到的action

HTTP Method URI Path Action Parameter
GET api/products GetAllPriducts none
GET api/products/4 GetPriductById 4
DELETE api/products/4 DeleteProduct 4
POST api/products no match  

注意URI中的{id}部分,如果出现的话,这部分的值将会被映射为action方法的名为id的参数。在这个例子里,controller定义了两个Get开头的方法,其中有一个有一个名为id的参数,另外一个无参数。

Route Variations(不知道怎么翻译,路由变体?)

除了使用命名约定以外,还可通过为action添加HttpGet,HttpPut,HttpPost或者HttpDelete特定来显示指定该action响应的Http method。

下面的例子中,FindProduct方法会对应到Http的Get请求:

public class ProductsController : ApiController
{
    [HttpGet]
    public Product FindProduct(id) {}
}

为了使一个action可以响应多种HTTP method,或者响应除了GET,PUT,POST,DELETE四种之外的其它HTTP method,可以为action指定AcceptVerbs特性,这个特性可以接受一个Http Method列表。

public class ProductsController : ApiController
{
    [AcceptVerbs("GET", "HEAD")]
    public Product FindProduct(id) { }

    // WebDAV method
    [AcceptVerbs("MKCOL")]
    public void MakeCollection() { }
}

通过名字进行路由(Routing by Action Name)

默认路由模板使用Http method来选择action,但是你也可以使用action的名字来进行路由。

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

在这个模板中,{action}占位符是controller中action的名字,这种形式的路由模板,通过附加在action之上的特性来确定该action响应哪种Http method,例如,假设controller中有如下的方法

public class ProductsController : ApiController
{
    [HttpGet]
    public string Details(int id);
}

在这个例子中,一个请求“api/products/details/1”的http get请求会被映射到Details方法,这种路由风格类似于ASP.NET MVC的路由风格,而且更适用于RPC-style API(远程过程调用风格的api?)

通过使用ActionName属性,我们可以指定特定的action名字,而不使用action的方法名,在下面的例子中,有两个action都会响应"api/products/thumbnail/id"这个uri,但是分别对应get method和post method:

public class ProductsController : ApiController
{
    [HttpGet]
    [ActionName("Thumbnail")]
    public HttpResponseMessage GetThumbnailImage(int id);

    [HttpPost]
    [ActionName("Thumbnail")]
    public void AddThumbnailImage(int id);
}

非action方法

对于controller中的方法,我们并不希望都会响应HTTP Method,也就是说controller中可以包含非action的方法,那么这时要给这些方法添加NonAction特性,这样Web Api框架在进行路由匹配的时候就会忽略这些方法。

// Not an action method.
[NonAction]  
public string GetPrivateData() { ... }
posted @ 2013-03-14 23:00  Lukexywang  阅读(2914)  评论(2编辑  收藏  举报