问题

怎么样可以使用更贴近资源(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-2)直接式路由/属性路由的更多相关文章

  1. [水煮 ASP.NET Web API2 方法论](3-8)怎样给指定路由配置处理器

    阅读导航 问题 解决方案 工作原理 代码演示 问题 如果仅仅针对指定的路由进行某些特定的消息处理,而不是应用于所有路由,我们应该怎么做呢? 解决方案 ASP.NET WEB API 的很多功能都内建了 ...

  2. [水煮 ASP.NET Web API2 方法论](3-9)空气路由的设置

    阅读导航 问题 解决方案 工作原理 代码演示 在此解释一下,空气路由,是本人臆想出来,觉着更能表达 IgnoreRoute 的意图,如果看着辣眼睛^^,请见谅. 问题 我们在之定义过集中式路由,集中式 ...

  3. [水煮 ASP.NET Web API2 方法论](3-5)路由约束

    问题 怎么样限制路由中参数的值. 解决方案 ASP.NET WEB API 允许我们通过 IHttpRouteConstraint 接口设置路由约束.集中式路由和直接式路由都可以使用 IHttpRou ...

  4. [水煮 ASP.NET Web API2 方法论](1-3)如何接收 HTML 表单请求

    问题 我们想创建一个能够处理 HTML表单的 ASP.NET Web API 应用程序(使用 application/x-www-form-urlencoded 方式提交数据). 解决方案 我们可以创 ...

  5. [水煮 ASP.NET Web API2 方法论](12-2)管理 OData 路由

    问题 如何控制 OData 路由 解决方案 为了注册路由,可以使用  HttpConfigurationExtension 类中 MapODataServiceRoute 的扩展方法.对于单一路由这样 ...

  6. [水煮 ASP.NET Web API2 方法论](1-5)ASP.NET Web API Scaffolding(模板)

    问题 我们想快速启动一个 ASP.NET Web API 解决方案. 解决方案 APS.NET 模板一开始就支持 ASP.NET Web API.使用模板往我们的项目中添加 Controller,在我 ...

  7. [水煮 ASP.NET Web API2 方法论](3-7)默认 Action 请求方式以及 NonActionAttribute

    问题 在 Controller 中有一个 public 的方法,但是又不想将这个 publlic 方法暴露成为一个 API. 解决方案 ASP.NET Web API 中,正常是通过 HTTP 谓词来 ...

  8. [水煮 ASP.NET Web API2 方法论](3-6)万能路由

    问题 定义什么样的路由,可以不会受请求参数类型和数量的限制,而被全部捕获? 解决方案 在路由模板中,给参数添加一个"*"前缀,例如 {*param},只要请求的 URL 能够和路由 ...

  9. [水煮 ASP.NET Web API2 方法论](3-4)设置路由可选项

    问题 怎么样创建一个路由,不管客户端传不传这个参数,都可以被成功匹配. 解决方案 ASP.NET WEB API 的集中式路由和属性路由都支持路由声明可选参数. 在用集中式路由中可以通过 RouteP ...

随机推荐

  1. 深入剖析 redis AOF 持久化策略

    本篇主要讲的是 AOF 持久化,了解 AOF 的数据组织方式和运作机制.redis 主要在 aof.c 中实现 AOF 的操作. 数据结构 rio redis AOF 持久化同样借助了 struct ...

  2. 调用CXF工具 生成 WSDL【转】

    在做WebService的时候,生成WSDL是必不可少的一步.我们通常使用的工具就是Axis和CXF. CXF提供了一个命令行工具,可以通过命令来生成Java to WSDL,也可以由WSDL生成Ja ...

  3. 第 3 章 MySQL 存储引擎简介

    第 3 章 MySQL 存储引擎简介 前言 3.1 MySQL 存储引擎概述 MyISAM 存储引擎是 MySQL 默认的存储引擎,也是目前 MySQL 使用最为广泛的存储引擎之一.他的前身就是我们在 ...

  4. android多国语言文件夹文件汇总

    android多国语言文件夹文件汇总如下: 中文(中国):values-zh-rCN 中文(台湾):values-zh-rTW 中文(香港):values-zh-rHK 英语(美国):values-e ...

  5. Filter之——GZIP全站压缩

    GZIP压缩:将压缩后的文本文件,发送给浏览器,减少流量. 一.进行gzip压缩条件: 1.请求头:Accept-Encoding : gzip  告诉服务器,该浏览器支持gzip压缩. 2.响应头: ...

  6. 飞思卡尔9S12X系列双核中的协处理器XGATE使用方法

    http://adi.chinaaet.com/analog/blogdetail/24482.html

  7. C8051 SMBus 原理

    一.SMBus总线   SMBus串行I/O接口完全符合系统管理总线规范 1.1 版.它是一个双线的双向串行总线,与I2C串行总线兼容.系统控制器对总线的读写操作都是以字节为单位的,由SMBus接口自 ...

  8. CentOS 7 Vmware虚拟机 /root空间不足解决方法(使用gparted live)

    1,关闭虚拟机,编辑虚拟机设置,增加虚拟磁盘的大小,我这里增加10GB 2,连接CDrom到ISO文件(gparted-live-0.19.0-1-i486.iso),使用gparted live启动 ...

  9. linux上java路径设置

    linux上java路径设置 标签: javalinuxpath 2012-04-30 22:14 1843人阅读 评论(0) 收藏 举报 版权声明:本文为博主原创文章,未经博主允许不得转载. 往/e ...

  10. RDLC报表 在WinForm里运行出现 未能加载文件或程序集microsoft.reportviewer.winforms

    做一下记录顺便帮助一下遇到问题的朋友. 做RDLC报表在WinForm运行,在VS里面调试引用了“Microsoft.ReportViewer.Common.dll”和“Microsoft.Repor ...