前言
阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看
路由就是Web API如何把URI匹配到一个Action的描述。Web API支持一种新的路由类型,被叫做属性路由。顾名思义,属性路由是用属性来创建路由。在你的Web API中属性路由可以让你更好的控制URI。你能容易的创建描述资源阶层的URIs。
较早的基于公约的路由风格是全面被支持的。事实上,你能够在同一个项目中联合使用这两种技术。
本文主要展示如何启用属性路由,并且描述了属性路由的各种选项,内容如下:
1、为什么使用属性路由?
2、启用属性路由
3、添加路由属性
4、路由前缀
5、路由约束
6、可选的URI参数和默认值
7、路由名称
8、路由顺序
1、为什么使用属性路由
第一个Web API版本使用的是基于公约的路由。在该类型的路由中, 你可以定义一个或者多个被参数化字符串的模版。当这个框架接收到一个请求时,它匹配一个URI到路由模版。有关基于公约的路由的详细介绍可以参考之前的文章:
基于公约的路由的一个优势就是,这个模版被定义在一个单独的地方。这个路由规则一致的被应用于所有的控制器。不幸的是,基于公约的路由是很难支持确切的URI模式,而这个确切的URI模式在Restful APIs中是很普遍的。例如,资源经常包含子资源:客户下了订单,电影有演员,书有作者等等,它是很自然的创建这些URI来反应这些关系:
/customers/1/orders
这种类型的URI在基于公约的路由下是比较难实现的。尽管它能做到,但是如果你有许多控制器或者很多资源类型这种结果不能很好的被扩展。
对于属性路由,它是很容易的为这个URI定义一个路由。你可以简单的添加一个属性到控制器的动作上:
[Route("customers/{customerId}/orders")] public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }
这有一些属性路由使它更容易的其他URI模式。
API版本控制
在下面的例子中,"api/v1/products"相对于"api/v2/products"将被路由到不同的控制器。
/api/v1/products /api/v2/products
重载URI片段
在下面的例子中,"1"是一个阶数,而"pending"被映射到集合。
/orders/1 /orders/pending
多个参数类型
在下面的例子中,"1"是一个阶数,而“2013/06/16”被指定为一个日期。
/orders/1 /orders/2013/06/16
2、启用属性路由
要启用属性路由,在配置期间需要调用MapHttpAttributeRoutes。这个扩展方法被定义在System.Web.Http.HttpConfigurationExtensions类中。
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); } }
你也可以将属性路由与基于公约的路由一起使用。为了定义基于公约的路由,需要调用MapHttpRoute 的方法。
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
3、添加路由属性
下面是一个使用属性定义的路由示例:
public class OrdersController : ApiController { [Route("customers/{customerId}/orders")] public IEnumerable<Order> FindOrdersByCustomer(int customerId) { ... } }
这个[Route]属性定义了一个HTTP Get方法。这个字符串“customers/{customerId}/orders”是路由的URI模版。在路由模版中的“{customerId}”参数匹配了在方法中的customerId参数的名称。 例如,这个路由将匹配如下的URI:
http://example.com/customers/1/orders
这个URI模版可以有多个参数:
[Route("customers/{customerId}/orders/{orderId}")] public Order GetOrderByCustomer(int customerId, int orderId) { ... }
任何没有路由属性的控制器方法将使用基于公约的路由。这种方式,你可以结合两种方式在同一个项目中。
4、路由前缀
通常情况下,在同一个控制器中的所有路由以相同的前缀开头。例如: