[水煮 ASP.NET Web API2 方法论](3-1)集中式路由
问题
怎样集中的定义路由
解决方案
通过调用 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)集中式路由的更多相关文章
- [水煮 ASP.NET Web API2 方法论](3-9)空气路由的设置
阅读导航 问题 解决方案 工作原理 代码演示 在此解释一下,空气路由,是本人臆想出来,觉着更能表达 IgnoreRoute 的意图,如果看着辣眼睛^^,请见谅. 问题 我们在之定义过集中式路由,集中式 ...
- [水煮 ASP.NET Web API2 方法论](3-6)万能路由
问题 定义什么样的路由,可以不会受请求参数类型和数量的限制,而被全部捕获? 解决方案 在路由模板中,给参数添加一个"*"前缀,例如 {*param},只要请求的 URL 能够和路由 ...
- [水煮 ASP.NET Web API2 方法论](3-4)设置路由可选项
问题 怎么样创建一个路由,不管客户端传不传这个参数,都可以被成功匹配. 解决方案 ASP.NET WEB API 的集中式路由和属性路由都支持路由声明可选参数. 在用集中式路由中可以通过 RouteP ...
- [水煮 ASP.NET Web API2 方法论](3-8)怎样给指定路由配置处理器
阅读导航 问题 解决方案 工作原理 代码演示 问题 如果仅仅针对指定的路由进行某些特定的消息处理,而不是应用于所有路由,我们应该怎么做呢? 解决方案 ASP.NET WEB API 的很多功能都内建了 ...
- [水煮 ASP.NET Web API2 方法论](3-5)路由约束
问题 怎么样限制路由中参数的值. 解决方案 ASP.NET WEB API 允许我们通过 IHttpRouteConstraint 接口设置路由约束.集中式路由和直接式路由都可以使用 IHttpRou ...
- [水煮 ASP.NET Web API2 方法论](3-3)路由默认值
问题 如何为路由中参数设置默认值. 解决方案 不管使用属性路由还是集中式路由,ASP.NET WEB API 都可以很方便的为路由定义默认参数.在每次客户端请求的时候,如果客户端没有传这些参数,框架会 ...
- [水煮 ASP.NET Web API2 方法论](3-2)直接式路由/属性路由
问题 怎么样可以使用更贴近资源(Controller,Action)的方式定义路由. 解决方案 可以使用属性路由直接在资源级别声明路由.只要简单的在 Action 上使用属性路由 RouteAttri ...
- [水煮 ASP.NET Web API2 方法论](1-5)ASP.NET Web API Scaffolding(模板)
问题 我们想快速启动一个 ASP.NET Web API 解决方案. 解决方案 APS.NET 模板一开始就支持 ASP.NET Web API.使用模板往我们的项目中添加 Controller,在我 ...
- [水煮 ASP.NET Web API2 方法论](3-7)默认 Action 请求方式以及 NonActionAttribute
问题 在 Controller 中有一个 public 的方法,但是又不想将这个 publlic 方法暴露成为一个 API. 解决方案 ASP.NET Web API 中,正常是通过 HTTP 谓词来 ...
随机推荐
- P3155 [CQOI2009]叶子的染色
P3155 [CQOI2009]叶子的染色 题目描述 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到 ...
- wepy
npm install -g cnpm --registry=https://registry.npm.taobao.org https://blog.csdn.net/qq_40414159/art ...
- Spring Boot 使用properties如何多环境配置
当我们使用properties文件作为Spring Boot的配置文件而不是yaml文件时,怎样实现多环境使用不同的配置信息呢? 在Spring Boot中,多环境配置的文件名需要满足 ...
- SQL语句(十八)—— 存储过程
存储过程 系统存储过程 自定义存储过程 扩展存储过程 一.创建存储过程 创建存储过程 --例1 USE SU GO Create Procedure SelProc AS Select * From ...
- Java入门系列(一)基础概览
序言 Java语言的特点不使用指针而使用引用.
- 《C语言程序设计基础I》秋季学习总结
希望下学期比这学期轻松,学习能力上升,只是越发丰富. 一步一步的走踏实了
- Eclipse中如何改变主题
童鞋们, eclipse主题太丑?想设置护眼的主题? 看看这些主题: 请移驾: Eclipse Color Themes 怎么设设置? 1. 打开”eclipse marketplace“, 如下图: ...
- python初步学习-python模块之 commands
commands 通过 os.popen() 执行 shell 命令,返回两个对象,一个是 状态码(Int).另一个为命令输出(str) commands.getoutput(cmd) 返回命令执行输 ...
- IIS 问题集锦
本文主要记录IIS中遇到的各种问题以及注意事项 一.在IIS中.NET Framework的版本选择为什么没有v3.0,v3.5? 首先需要澄清的是这里有两个关于版本的东西:ASP.NET和.NET ...
- Hibernate5笔记5--关联关系映射
关联关系映射: 关联关系,是使用最多的一种关系,非常重要.在内存中反映为实体关系,映射到DB中为主外键关系.实体间的关联,即对外键的维护.关联关系的发生,即对外键数据的改变. 外键:外面的主键,即,使 ...