[水煮 ASP.NET Web API2 方法论](3-2)直接式路由/属性路由
2016-11-25 08:06
351 查看
问题
怎么样可以使用更贴近资源(Controller,Action)的方式定义路由。
解决方案
可以使用属性路由直接在资源级别声明路由。只要简单的在 Action 上使用属性路由 RouteAttribute,然后传一个相关路由模板就可以。属性路由与集中式路由在路由模板含义上基本是一样的,所有路由参数应该使用花括号,同时要与使用的 Action 相匹配。直接式路由支持默认路由,可选参数,约束。详细分析请往下走。
要是启用属性路由的话,需要在应用程序启动的位置,使用 HttpConfiguration 调用 MapAttributeRoutes 的扩展方法。
工作原理
一个叫做 Attribute Routing 的开源类库已经成为了 ASP.NET WEB API 2 架构的核心部分。随之而来的是,解决了集中式路由在维护上给我们带来的痛苦,允许我们直接在 Controller 和 Action 上声明路由。
对于大多数开发者来说,与集中式路由相比,属性路由(上面所说的直接路由)是更加自然的方法,属性路由强调的是 WEB API 资源和 URI 之间的直接关系,URI 资源应该是可以通过 HTTP 直接访问。事实上,还是有一些流行的 .NET Web 框架,例如,ServiceStack、NancyFx 都有自己的方式来定义这种贴近资源的路由(嵌入资源)。
在应用程序启动时,调用 MapHtpAtrributeRoutes,其实是告诉 ASP.NET WEB API 扫描所有 Controller 上声明的属性路由。
究其缘由,属性路由的声明和集中式路由没有太大的区别。而且,他们的路由都是被添加到与前面上一篇集中式路由代码片段 3-1 一样的路由集合中。最大的不同就是,直接式路由(属性路由)是作为单一复合路由(内部的 SubRouteCollection 类型)被添加到路由集合中的,使用的路由 key 是 MS_attributerouteWebApi。
处理每个属性路由的时候,Controller(HttpControllerDescriptor)或 Action(HttpActionDescriptor)会标记出能够访问到的属性路由。这个过程的完成是通过在这些 descriptor 类型的 Properties 字典中添加 MS_IsAttributeRouted。
属性路由提供了一些路由自定义处理。事实上,不必强制在 Controller 和 Action 上使用 RouteAttribue 声明路由。通过实现 IDirectRouteFactory,可以自定义属性路由、甚至无属性路由,集中式逻辑路由。IDirectRouteFactory 的使用 和 IDirectRouteProvider 会在后面的 3-11 篇和 6-8 篇的时候再次讨论。
代码演示
与集中式路由相反,属性路由显得很自然,直接展示了 Controller 和 Action 之间的关系,也很容易声明复杂的路由。如代码片段 3-4 例子所示。
代码片段 3-4. 声明简单的属性路由
属性路由也允许通过 RoutePrefixAttribute 定义路由前缀。但,只能在 Controller 级别声明,修改代码片段 3-4,为这个 Controller 中所有的路由定义一个公用前缀。使用 RoutePrefixAttribute 重写,如代码片段 3-5 所示。需要注意的是,当路由被显示的时候,所有在 Action 上指定的 RouteAttribute 是路由模板的一部分,被拼接在 RoutePrefixAttribute 之后。
代码片段 3-5. 属性路由和路由前缀
与集中式路由相同的是,属性路由也是依赖 HTTP 谓词分发。所以,由于对路由定义命名的约定(上一篇描述了 HTTP 谓词分发),代码片段 3-4 和 3-5 只能处理 HTTP GET 请求。
为了可以支持其他 HTTP 谓词类型,再在 Controller 中加几个 Action ,命名的时候,前缀使用 HTTP 谓词相关的动词或者标签。代码片段 3-6 有 POST 和 PUT 两个类型的 Action。他们都扩展了 TeamsController 的功能,可以创建 Team 资源,创建一个 Player 资源到一个给定的 Team 中,这两个都是 POST,以及一个更新 Team 的操作(PUT)。
代码片段 3-6. 补充定义,支持其他的 HTTP 谓词
怎么样可以使用更贴近资源(Controller,Action)的方式定义路由。
解决方案
可以使用属性路由直接在资源级别声明路由。只要简单的在 Action 上使用属性路由 RouteAttribute,然后传一个相关路由模板就可以。属性路由与集中式路由在路由模板含义上基本是一样的,所有路由参数应该使用花括号,同时要与使用的 Action 相匹配。直接式路由支持默认路由,可选参数,约束。详细分析请往下走。
[Route("api/teams/{id}")] public Team GetTeam(int id) { //忽略逻辑 }
要是启用属性路由的话,需要在应用程序启动的位置,使用 HttpConfiguration 调用 MapAttributeRoutes 的扩展方法。
Config.MapHttpAttributeRoutes();
工作原理
一个叫做 Attribute Routing 的开源类库已经成为了 ASP.NET WEB API 2 架构的核心部分。随之而来的是,解决了集中式路由在维护上给我们带来的痛苦,允许我们直接在 Controller 和 Action 上声明路由。
对于大多数开发者来说,与集中式路由相比,属性路由(上面所说的直接路由)是更加自然的方法,属性路由强调的是 WEB API 资源和 URI 之间的直接关系,URI 资源应该是可以通过 HTTP 直接访问。事实上,还是有一些流行的 .NET Web 框架,例如,ServiceStack、NancyFx 都有自己的方式来定义这种贴近资源的路由(嵌入资源)。
在应用程序启动时,调用 MapHtpAtrributeRoutes,其实是告诉 ASP.NET WEB API 扫描所有 Controller 上声明的属性路由。
究其缘由,属性路由的声明和集中式路由没有太大的区别。而且,他们的路由都是被添加到与前面上一篇集中式路由代码片段 3-1 一样的路由集合中。最大的不同就是,直接式路由(属性路由)是作为单一复合路由(内部的 SubRouteCollection 类型)被添加到路由集合中的,使用的路由 key 是 MS_attributerouteWebApi。
处理每个属性路由的时候,Controller(HttpControllerDescriptor)或 Action(HttpActionDescriptor)会标记出能够访问到的属性路由。这个过程的完成是通过在这些 descriptor 类型的 Properties 字典中添加 MS_IsAttributeRouted。
属性路由提供了一些路由自定义处理。事实上,不必强制在 Controller 和 Action 上使用 RouteAttribue 声明路由。通过实现 IDirectRouteFactory,可以自定义属性路由、甚至无属性路由,集中式逻辑路由。IDirectRouteFactory 的使用 和 IDirectRouteProvider 会在后面的 3-11 篇和 6-8 篇的时候再次讨论。
代码演示
与集中式路由相反,属性路由显得很自然,直接展示了 Controller 和 Action 之间的关系,也很容易声明复杂的路由。如代码片段 3-4 例子所示。
代码片段 3-4. 声明简单的属性路由
public class TeamsController : ApiController { [Route("api/teams/{id}")] public Team GetTeam(int id) { //忽略逻辑 } [Route("api/teams")] public IEnumerable<Team> GetTeams() { //忽略逻辑 } [Route("api/teams/{teamId}/players")] public IEnumerable<Player> GetPlayers(int teamId) { //忽略逻辑 } }
属性路由也允许通过 RoutePrefixAttribute 定义路由前缀。但,只能在 Controller 级别声明,修改代码片段 3-4,为这个 Controller 中所有的路由定义一个公用前缀。使用 RoutePrefixAttribute 重写,如代码片段 3-5 所示。需要注意的是,当路由被显示的时候,所有在 Action 上指定的 RouteAttribute 是路由模板的一部分,被拼接在 RoutePrefixAttribute 之后。
代码片段 3-5. 属性路由和路由前缀
[RoutePrefix("api/teams")] public class TeamsController : ApiController { [Route("{id}")] public Team GetTeam(int id) { // 忽略逻辑 } [Route] public IEnumerable<Team> GetTeams() { // 忽略逻辑 } [Route("{teamId}/players")] public IEnumerable<Player> GetPlayers(int teamId) { // 忽略逻辑 } }
与集中式路由相同的是,属性路由也是依赖 HTTP 谓词分发。所以,由于对路由定义命名的约定(上一篇描述了 HTTP 谓词分发),代码片段 3-4 和 3-5 只能处理 HTTP GET 请求。
为了可以支持其他 HTTP 谓词类型,再在 Controller 中加几个 Action ,命名的时候,前缀使用 HTTP 谓词相关的动词或者标签。代码片段 3-6 有 POST 和 PUT 两个类型的 Action。他们都扩展了 TeamsController 的功能,可以创建 Team 资源,创建一个 Player 资源到一个给定的 Team 中,这两个都是 POST,以及一个更新 Team 的操作(PUT)。
代码片段 3-6. 补充定义,支持其他的 HTTP 谓词
[Route] public HttpResponseMessage PostTeam(Team team) { // 忽略逻辑 } [HttpPost] [Route("{teamId}/players")] public HttpResponseMessage AddPlayer(int teamId, Player player) { // 忽略逻辑 } [Route("{id}")] public HttpResponseMessage PutTeam(int id, Team team) { // 忽略逻辑 }
相关文章推荐
- [水煮 ASP.NET Web API2 方法论](3-6)万能路由
- [水煮 ASP.NET Web API2 方法论](3-3)路由默认值
- [水煮 ASP.NET Web API2 方法论](3-8)怎样给指定路由配置处理器
- [水煮 ASP.NET Web API2 方法论](3-5)路由约束
- [水煮 ASP.NET Web API2 方法论](12-2)管理 OData 路由
- [水煮 ASP.NET Web API2 方法论](3-9)空气路由的设置
- [水煮 ASP.NET Web API2 方法论](3-4)设置路由可选项
- [水煮 ASP.NET Web API2 方法论](3-1)集中式路由
- [水煮 ASP.NET Web API2 方法论](1-4)从 MVC Controller 链接到 API Controller 以及反向链接
- [水煮 ASP.NET Web API2 方法论](1-6)Model Validation
- [水煮 ASP.NET Web API2 方法论](1-8)添加 Session 状态
- [水煮 ASP.NET Web API2 方法论](1-7)CSRF-Cross-Site Request Forgery
- [水煮 ASP.NET Web API2 方法论](1-1)在MVC 应用程序中添加 ASP.NET Web API
- [水煮 ASP.NET Web API2 方法论](12-4)OData 支持的 Function 和 Action
- [水煮 ASP.NET Web API2 方法论](12-1)创建 OData
- [水煮 ASP.NET Web API2 方法论](1-3)如何接收 HTML 表单请求
- [水煮 ASP.NET Web API2 方法论](1-6)Model Validation
- [水煮 ASP.NET Web API2 方法论](3-7)默认 Action 请求方式以及 NonActionAttribute
- [水煮 ASP.NET Web API2 方法论](1-8)添加 Session 状态
- [水煮 ASP.NET Web API2 方法论](12-3)OData 查询