【翻译】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() { ... }