问题

怎样集中的定义路由

解决方案

通过调用 HttpRouteCollectionExtension 类中的 MapHttpRoute 扩展方法在 HttpRouteCollection 中定义路由,可以通过 HttpConfiguration 对象调用。

最基础的使用就是定义一个非常通用的路由模板,他会通过 {controller} 占位符匹配所有的 Controller。如代码片段 3-1 所示。

代码片段 3-1. ASP.NET WEB API 默认定义的路由以及一个简单的 Controller

 config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new {id = RouteParameter.Optional}
); public class OrdersController : ApiController
{
public Order Get(int id)
{
// 忽略逻辑
}
}

在路由模板中,可以定义自己的占位符,如代码片段 3-1 所示的 {id}。他与 Action 中的参数名称相匹配匹配,ASP.NET WEB API 会从 request 中提取出相应的值,传入 Action 方法中。也就是,代码片段 3-1 中 OrdersController 的 Get请求方法的这种情

况。

工作原理

从最初版本开始,ASP.NET WEB API 就一直使用集中式路由维护路由表,这和 MVC 如出一辙。

ASP.NET WEB API 定义了很多 MapHttpRoute 的变种。所需参数最少的一个方法,只需要一个路由模板和一个路由名称。

 public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name,
string routeTemplate)

除声明简单基础路由以外的方式,也可以通过默认值和约束,或者设置每个路由消息处理程序,将会在下面的章节介绍这个。所有的这些操作都是通过 Map HttpRoute 的重载方法实现的。

 public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name,
string routeTemplate, object defaults) public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name,
string routeTemplate, object defaults, object constraints) public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name,
string routeTemplate, object defaults, object constraints, HttpMessageHandler handler)

通过路由默认值,可以直接定位到路由相关的 Controller;可是,这样的特定路由需要定义在通用路由之前,也就是代码片段 3-1 的路由之前。原因就是,路由是顺序匹配的,路由在选定处理一个 HTTP 请求的时候,是在每次请求的时候,扫描路由集合中的所有路由,选用第一个被匹配的路由模板。简单的说,越是特殊的路由定义越靠前,越是通用的路由定义越靠后。

在  Self-hosting 中,ASP.NET WEB API 是以 IDictionary<stirng, IHttpRoute> 的形式在维护路由,Idictionary<string, IHttpRoute> 是在 HttpRouteCollection 类中。在 Web host 中也提供了 System.Web.Routing.RouteCollection 的扩展方法,因此,可以直接在这个里面定义 ASP.NET WEB API 路由。

RouteTable.Routes.MapHttpRoute("DefaultApi", "api/{controller}")

如果使用 ASP.NET 运行时 host WEB API,无论使用什么扩展方法声明路由,都会被添加到同一个 RouteTable 中。内部是通过一个叫做 HostedHttpRouteCollection 的类来实现的,这个类是 HttpRouteCollection 的子类,而不是在字典(比如 self-host)中维护路由,所有转发路由都是查找 System.Web.RouteCollection。

ASP.NET WEB API 与 ASP.NET MVC 是不一样的,API 使用的是基于 HTTP 谓词匹配来处理一个 Controller 请求。换句话说,框架会根据 HTTP 的东西来选择一个 Action 处理请求,选择的逻辑如下:

  • 通过方法名推断 HTTP 谓词,如果名字类似于 PostOrder、GetById 等等。
  • 通过 Action 属性推断 HTTP 谓词。
  • Action 参数定义与路由模板必须匹配。

典型的 ASP.NET WEB API 路由是指向资源的。可以通过 HTTP  谓词调用,还需要除了 Action 之外的参数。如代码片段 3-1 所示的默认路由,可以匹配如下请求:

  • GET myapi.com/api/orders
  • POST myapi.com/api/inovice
  • PUT myapi.com/api/invice/2

小提示 在 ASP.NET WEB API 是可以使用 RPC 的,具体细节会在 3-6 介绍。

代码演示

ASP.NET WEB API 是基于 HTTP 谓词进行分发逻辑的,不像 ASP.NET MVC,很容易出现 AmbiguousMatchEception。例如,可以设想一些使用代码片段 3-1 的路由的例子。

如代码片段 3-2 所示的例子,这三个方法都是可以处理相同的 GET 请求,如,/api/orders/1.

代码片段 3-2.

代码片段 3-2. ASP.NET WEB API Controller

 public class BadOrdersController : ApiController
{
[HttpGet]
public Order FindById(int id)
{
// 忽略逻辑
} public Order GetById(int id)
{
// 忽略逻辑
} public Order Get(int id)
{
// 忽略逻辑
}
}

同时我们需要注意,定义复杂、多等级、嵌套路由的时候,集中式路由变得有点麻烦。考虑如下路由

  • GET myapi.com/api/teams
  • GET myapi.com/api/teams/1
  • GET myapi.com/api/teams/1/players

使用集中式路由,可以在 Controller 中使用如下三个方法;然而,我们必须注意路由之间冲突的问题,因为有两个 GET 方法都是只使用了一个 int 的参数。如代码片段 3-3 所示。有一个特殊的路由指出了 URI 中包含 /players/ 段会被匹配到,而且这个路由定义在通用路由之前。

代码片段 3-3 使用集中式路由配置嵌套路由

 public class TeamsController : ApiController
{
public Team GetTeam(int id)
{
// 忽略逻辑
}
public IEnumerable<Team> GetTeams()
{
// 忽略逻辑
}
public IEnumerable<Player> GetPlayers(int teamId)
{
// 忽略逻辑
}
} config.Routes.MapHttpRoute(
name: "players",
routeTemplate: "api/teams/{teamid}/players",
defaults: new {controller = "teams"}
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

集中式路由的主要问题是,特殊路由的定义,仅仅是处理特殊的 Controller 特殊的 Action。通过定义特殊路由并添加到一般路由之前,在人为干预下短路了路由匹配。

这种处理并不是最理想,当应用程序变大之后,会有更复杂的、多层级的路由,可能就要在集中式路由中痛苦的挣扎(路由维护和调试)。更好的选择就是使用直接式路由,下一篇 3-2 定义直接路由,以及后面介绍路由的时候都会涉及直接式路由。

[水煮 ASP.NET Web API2 方法论](3-1)集中式路由的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. [水煮 ASP.NET Web API2 方法论](3-3)路由默认值

    问题 如何为路由中参数设置默认值. 解决方案 不管使用属性路由还是集中式路由,ASP.NET WEB API 都可以很方便的为路由定义默认参数.在每次客户端请求的时候,如果客户端没有传这些参数,框架会 ...

  7. [水煮 ASP.NET Web API2 方法论](3-2)直接式路由/属性路由

    问题 怎么样可以使用更贴近资源(Controller,Action)的方式定义路由. 解决方案 可以使用属性路由直接在资源级别声明路由.只要简单的在 Action 上使用属性路由 RouteAttri ...

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

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

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

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

随机推荐

  1. mongo ttl索引

    db.log_events.find()                                     # 查找log_events里的所有数据   db.log_events.create ...

  2. PHP常亮

    define('PI','3.14'); echo PI; 名字大写,创建后不能修改和销毁 销毁变量用unset()

  3. bzoj千题计划144:bzoj1176: [Balkan2007]Mokia

    http://www.lydsy.com/JudgeOnline/problem.php?id=1176 CDQ分治 #include<cstdio> #include<iostre ...

  4. 在WindowsServer2008服务器上安装SQLServer2008R2 Express版

    登录服务器 使用远程桌面登录Windows Server 2008   安装前的准备工作 下载SQL Server安装程序 下载Microsoft SQL Server2008 R2 RTM - Ex ...

  5. Linux系统接入小区宽带

    jollywing(jollywing@foxmail.com) 安装 rp-pppoe 今天去联通营业厅开通了家庭宽带,回到家就搜索怎么用Linux接入小区宽带,发现大多数人都选择用PPPOE拨号上 ...

  6. Donald Ervin Knuth:最年轻的图灵奖高德纳

    高德纳(Donald Ervin Knuth,1938年),美国著名计算机科学家,斯坦福大学电脑系荣誉教授.高德纳教授被誉为现代计算机科学的鼻祖,在计算机科学及数学领域发表了多部 具广泛影响的论文和著 ...

  7. laravel带条件查询手动分页

    后台php代码: //手动分页 $users = $kaoqin; //打算输出的数组,二维 $perPage = 10; if ($request->has('page')) { $curre ...

  8. Mother's Mil 母亲的牛奶

    Description 农民约翰有三个容量分别是A,B,C升的桶,A,B,C分别是三个从1到20的整数,最初,A和B桶都是空的,而C桶是装满牛奶的.有时,约翰把牛奶从一个桶倒到另一个桶中,直到被灌桶装 ...

  9. webrtc前景如何

    首先WebRTC是什么? WebRTC --- Web browsers with Real-Time Communications (RTC). WebRTC是一个免费.开放的项目.使web浏览器通 ...

  10. JS设计模式——12.装饰者模式

    装饰者模式概述 本章讨论的是一种为对象添加特性的技术,她并不使用创建新子类这种手段. 装饰者模式可以用来透明的把对象包装在具有同样接口的另一个对象中.这样一来,就可以给一个方法添加一些行为,然后将方法 ...