问题

怎么样可以使用更贴近资源(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. 【卡西欧Fx5800-p程序】01 坐标转换程序-带注释

    1.程序说明: DDSG  (大地坐标转施工坐标) SGDD  (施工坐标转大地坐标) ↙      (回车命令"EXE") K       (施工坐标转换原点在线性上的桩号,如果 ...

  2. 文件编辑器 vi

    1.关于文本编辑器: 文本编辑器有很多,比如图形模式的gedit.kwrite.OpenOffice ... ... ,文本模式下的编辑器有vi.vim(vi的增强版本)和nano ... ... v ...

  3. Asp.net Core 1.0.1升级到Asp.net Core 1.1.0 Preview版本发布到Windows Server2008 R2 IIS中的各种坑

    Asp.net Core 1.0.1升级到Asp.net Core 1.1.0后,程序无法运行了 解决方案:在project.json中加入runtime节点 "runtimes" ...

  4. AIDL示例

    背景 最近在考虑项目重构的时候,考虑将项目拆分成两个APK,一个用于数据服务,一个用于UI展示. 数据服务APK向自己编写APK提供数据,同时也可以向第三方提供数据.考虑使用这样的方式代替向第三方提供 ...

  5. C primer plus 练习题 第二章

    6. #include <stdio.h> void echo(); int main() { /* echo(); echo(); echo(); printf("\n&quo ...

  6. 使用NSKeyedArchiver归档

    将各种类型的对象存储到文件中,而不仅仅是字符串.数组和字典类型,有一种更灵活的方法.就是利用NSKeyedAarchiver类创建带键(keyed)的档案来完成. Mac OS X从版本10.2开始支 ...

  7. Windows下启动各服务命令

    1. gpedit.msc-----组策略 2. nslookup-------IP地址侦测器 3. explorer-------打开资源管理器 4. logoff---------注销命令 5. ...

  8. 现在看看自己写的博客,怎么感觉好low啊。。。

    是不会写还是怎么着? 感觉比较好的东西,难以整理,就没往上放.... 现在猛一看,博客里的东西乱七八糟的...各位看官随便看看就好

  9. Eclipse 常用最新插件.标记

    Properties Editor     编辑java的属性文件,并可以自动存盘为Unicode格式 http://marketplace.eclipse.org/content/propertie ...

  10. 使用SharePoint Designer定制开发专家库系统实例!

    将近大半年都没有更新博客了,趁这段时间不忙,后续会继续分享一些技术和实际应用.对于Sharepoint的定制开发有很多种方式,对于一般的应用系统,可以使用Sharepoint本身自带的功能,如列表作为 ...