2.2WebApi路由在Action上
这篇文章描述 ASP.NET Web API 如何将 HTTP 请求路由到特定的操作在控制器上。
有关路由的高级别概述,请参见ASP.NET Web API 的路由.
本文着眼于路由进程的详细信息。如果你创建一个 Web API 项目并发现一些请求不要路由你期望的方式,希望这篇文章将帮助。
路由具有三个主要阶段 ︰
- 匹配的 URI 到工艺路线模板。
- 选择一个控制器。
- 选择操作。
您可以用您自己的自定义行为替换一些零件的过程。在本文中,我描述的默认行为。最后,我注意到的地方,在那里你可以自定义的行为。
工艺路线模板
工艺路线模板看起来类似于 URI 路径,但它可以有占位符值,用花括号表示 ︰
"api/{controller}/public/{category}/{id}"
当你创建一个路由时,您可以为部分或全部的占位符提供默认值 ︰
您还可以提供约束,限制如何 URI 段可以匹配一个占位符 ︰
框架会尝试匹配模板的 URI 路径中的段。在模板中的文本必须完全匹配。占位符匹配任何价值,除非你指定的约束。框架与其他部分的 URI,如主机名或查询参数不匹配。框架将匹配 URI 路由表中选择的第一个路由。
有两个特别占位符:"{控制器}"和"{}"。
- "{}"控制器提供的控制器的名称。
- "行动 》 {}"提供的操作的名称。在 Web API 中,通常的约定是省略"的行动 {}"。
默认值
如果您提供默认值,该路由将与匹配 URI,它缺少这些段。例如 ︰
"Http://localhost/api/products"URI 匹配这条路线。"{类别}"段分配的默认值"全部"。
路由字典
如果框架找到了匹配的 URI,它会创建一个字典,包含为每个占位符的值。键是占位符名称,不包括大括号。这些值被从 URI 路径或默认值。这本词典存储在IHttpRouteData对象中。
在此路由匹配的阶段,特别"{}"控制器和"的行动 {}"占位符治疗就像其他占位符。它们只存储在字典中,其他值。
默认情况下可以有RouteParameter.Optional的特殊价值。如果占位符获取指定此值,值不是添加到路由字典。例如 ︰
对于"api/产品"的 URI 路径,路由字典将包含 ︰
- 控制器:"产品"
- 类别:"所有人"
然而,对于"api/产品/玩具/123",路由字典将包含 ︰
- 控制器:"产品"
- 类别:"玩具"
- id:"123"
默认设置也可以在路线模板中包含一个值未在任何地方出现。如果该路由匹配,该值存储在字典中。例如 ︰
如果 URI 路径是"api/根/8",这本字典将包含两个值 ︰
- 控制器:"客户"
- id:"8"
选择控制器
由IHttpControllerSelector.SelectController方法处理控制器所选内容。此方法采用HttpRequestMessage的实例,并返回HttpControllerDescriptor。由DefaultHttpControllerSelector类提供默认实现。此类使用一种简单的算法 ︰
- 在路由字典键"控制器"中查找。
- 采取此键的值和追加字符串"控制器",得到控制器的类型名称。
- 寻找与此类型名称的 Web API 控制器。
例如,如果路由字典包含键-值对"控制器"="产品",然后是控制器的类型是"ProductsController"。如果没有匹配的类型或多个匹配项,框架向客户端返回错误。
步骤 3, DefaultHttpControllerSelector使用IHttpControllerTypeResolver接口获取 Web API 控制器类型的列表。IHttpControllerTypeResolver的默认实现返回所有的公共类的 (a) 执行IHttpController,(b) 是不抽象,和 (c) 有一个名称,在"控制器"中结束。
选择动作
选择控制器后, 框架通过调用IHttpActionSelector.SelectAction方法将选择的行动。此方法采用HttpControllerContext并返回HttpActionDescriptor.
由ApiControllerActionSelector类提供默认实现。若要选择一个动作,它看起来在以下 ︰
- 请求的 HTTP 方法。
- 在工艺路线模板中,如果存在"的行动 {}"占位符。
- 在控制器上的操作的参数。
选择算法之前,我们需要了解一些控制器操作的东西。
在控制器上的方法被视为"行动"?当选择某个操作,框架只是看看公共实例方法的控制器上。此外,它排除了"特别的名字"方法 (构造函数、 事件、 运算符重载,等等),和从继承的方法ApiController类。
的 HTTP 方法。框架只选择匹配的要求,确定如下的 HTTP 方法的行为 ︰
- 您可以使用属性指定的 HTTP 方法 ︰ AcceptVerbs、 HttpDelete、公共、 HttpHead、 HttpOptions、 HttpPatch、 HttpPost或HttpPut.
- 否则,如果控制器方法的名称以"Get"、"开机自检"、"放"、"删除"、"头"、"选项"或"修补程序"开头,然后由公约行动支持的 HTTP 方法。
- 如果以上都不是,该方法支持邮政。
参数绑定。参数绑定是如何 Web API 创建参数的值。参数绑定的默认规则是这样的 ︰
- 简单类型是采取从 URI。
- 复杂类型是取自请求正文。
简单类型包括所有的.NET 框架基元类型,加上日期时间、十进制、 Guid,字符串和时间跨度。为每个操作,顶多一个参数可以读取请求正文。
它是可以重写默认绑定规则。请参见WebAPI 参数绑定引擎盖下.
与这种背景下,这里是行动选择算法。
- 在匹配的 HTTP 请求方法的控制器上创建的所有操作的列表。
- 如果路由字典有的"操作"项,删除其名称与此值不匹配的操作。
- 尝试匹配到的 URI,操作参数,如下所示 ︰
- 为每个操作,得到是一个简单的类型,其中绑定从 URI 获取参数的参数的列表。排除的可选参数。
- 从该列表中,试着找到适合每个参数的名称,或者路由字典或 URI 的查询字符串中。匹配项是区分大小写,并不依赖于参数顺序。
- 选择列表中的每个参数在 URI 匹配操作。
- 如果更多这一行动符合这些标准,挑选一个有大多数的参数匹配。
- 忽略[侵权]属性的行动。
步骤 #3 是最容易混淆的。其基本思想是一个参数可以获取其值,从 URI,从请求正文中,或从自定义绑定。对于来自 URI 的参数,我们想要确保 URI 实际上包含该路径 (通过路由字典) 中或在查询字符串中的参数的值。
例如,请考虑以下行动 ︰
Id参数绑定到的 URI。因此,这一行动只能匹配一个 URI,它包含"身份证号",在路由字典或查询字符串中的值。
可选参数是个例外,因为它们是可选的。为可选的参数,它是确定如果绑定不能从 URI 中获取价值。
复杂类型是个例外,出于不同的原因。复杂类型通过自定义绑定只能绑定到的 URI。但在这种情况下,框架不能预先知道是否该参数会绑定到特定的 URI。为了找到答案,它将需要调用绑定。选择算法的目标是从静态描述,在调用任何绑定之前选择的操作。因此,复杂类型被排除的匹配算法。
选择操作后,所有的参数绑定调用。
摘要 ︰
- 行动必须匹配请求的 HTTP 方法。
- 如果目前操作名称必须匹配路由字典中的"行动"条目。
- 为每个参数的作用,如果该参数是从 URI,然后参数名称必须找到路由字典或 URI 的查询字符串中。(可选参数和复杂类型的参数除外。)
- 尝试匹配最多的参数。最佳匹配可能是一种不带任何参数的方法。
扩展的示例
路线 ︰
routes.MapHttpRoute(
name: "ApiRoot",
routeTemplate: "api/root/{id}",
defaults: new { controller = "products", id = RouteParameter.Optional }
);
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
控制器 ︰
public class ProductsController : ApiController
{
public IEnumerable<Product> GetAll() {}
public Product GetById(int id, double version = 1.0) {}
[HttpGet]
public void FindProductsByName(string name) {}
public void Post(Product value) {}
public void Put(int id, Product value) {}
}
HTTP 请求 ︰
GET http://localhost:34701/api/products/1?version=1.5&details=1
路由匹配
URI 与路由匹配的名为"DefaultApi"。路由字典包含以下项 ︰
- 控制器:"产品"
- id:"1"
路由字典不包含查询字符串参数、"版本"和"详细信息",但这些仍被视为在行动选择。
控制器所选内容
从路由字典中的"控制器"条目,控制器类型是ProductsController
.
选择动作
HTTP 请求是 GET 请求。支持 GET 的控制器行为是GetAll
、 GetById
和FindProductsByName
。路由字典不包含"行动"的条目,所以我们不需要匹配的操作名称。
接下来,我们尝试匹配参数名称的操作,只看得到的行动。
行动 | 匹配的参数 |
---|---|
GetAll |
没有一个 |
GetById |
""id |
FindProductsByName |
"名称" |
请注意,不是GetById
的版本参数,因为它是一个可选的参数。
GetAll
方法匹配琐细。GetById
方法也相匹配,因为路由字典包含"id"。FindProductsByName
方法不匹配。
GetById
方法赢了,因为它与一个参数,与GetAll
没有参数相匹配。用下面的参数值调用该方法 ︰
- id = 1
- 版本= 1.5
请注意,即使在选择算法不使用版本,参数的值来自 URI 的查询字符串。
扩展点
Web API 的某些部件中的路由选择进程提供了扩展点。
为任何这些接口提供自己的实现,请使用HttpConfiguration对象上的服务集合 ︰
2.2WebApi路由在Action上的更多相关文章
- 爱上MVC3~在控制器或Action上动态设定模板页(Layout)
回到目录 很多境况下,我们需要设置自己模块的layout,即它的布局页面,在MVC2中叫它模板页面,你可以在return view方法时设置它,当然,这不是一种好方法,因为我不想每个action都去设 ...
- WebApi:路由和Action选择
译自:http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection ...
- struts2,action上传文件
通过servlet实现文件上传,可以用用servlet接受到request的值的话:主要是这句话 List<?> items = upload.parseRequest(request); ...
- vue-router 获得上一级路由以及返回上一级路由的方法
if (this.$store.state.previousRouter.name) { this.$router.push({name: this.$store.state.previousRout ...
- 首页重定位到mian.action上
<body onload="top.location.href='<%=request.getContextPath()%>/main.action';">
- asp.net core的授权过滤器中获取action上的Attribute
var action = context.ActionDescriptor as ControllerActionDescriptor; var permission = action.MethodI ...
- MVC POST在ACTION上进行多个模型的数据绑定
首先声明,接下来的东西并不符合本人认同的严谨的MVC模式. 用MVC做项目的过程中,越来越多的用到不严谨的MVC编程. 比如,在"cshtml"文件中写: @Html.Raw(DB ...
- 工作总结 [ActionName("ss123")] 更改路由中Action名称 获取或设置操作的名称
- 解读ASP.NET 5 & MVC6系列(11):Routing路由
新版Routing功能介绍 在ASP.NET 5和MVC6中,Routing功能被全部重写了,虽然用法有些类似,但和之前的Routing原理完全不太一样了,该Routing框架不仅可以支持MVC和We ...
随机推荐
- POJ2794 Double Patience[离散概率 状压DP]
Double Patience Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 694 Accepted: 368 Cas ...
- 第1章 Linux系统简介
第1节 UNIX发展历史和发行版本 1. UNIX与Linux发展史 1.1 UNIX发展历史 (1)1965年,美国麻省理工学院(MIT).通用电气公司(GE)及AT&T的贝尔实验室联合开发 ...
- PhpStorm XDebug 远程调试
现在我们自己公司的各种开发和测试服务器,都是使用阿里云的服务器.一些PHP的项目,无法在本地搭建完整的环境,在外网服务器上调试更方便定位问题.发现网上没有完整的关于如何配置PHPStorm和XDebu ...
- 从贝叶斯到粒子滤波——Round 2
上一篇博文已经讲了贝叶斯滤波的原理以及公式的推导:http://www.cnblogs.com/JunhaoWu/p/bayes_filter.html 本篇文章将从贝叶斯滤波引入到粒子滤波,讲诉粒子 ...
- 关于javascript中this的那点事
this可谓是JavaScript中的开发神器,使用得当的话不仅有事半功倍的效果,而且代码的逼格也更高.但是既然是神器,如果你没有足够的功力的话,那么就不要使用它,否则就有可能自毁身亡.曾几何时,我偶 ...
- a href=#与 a href=javascript:void(0) 的区别
a href="#"> 点击链接后,页面会向上滚到页首,# 默认锚点为 #TOP <a href="javascript:void(0)" onCl ...
- java画图之初体验
1.实现画图程序所需的API类 JFrame JButton ActionListener 动作事件接口 ActionEvent ...
- K-means聚类算法
聚类分析(英语:Cluster analysis,亦称为群集分析) K-means也是聚类算法中最简单的一种了,但是里面包含的思想却是不一般.最早我使用并实现这个算法是在学习韩爷爷那本数据挖掘的书中, ...
- python select 实现
python的select()方法直接调用操作系统的IO接口 它监控sockets,openfiile,pipes (所有带fileno()的方法的文件句柄) 什么时候变成 readable writ ...
- 什么是js面向对象??
简单的来说就是键值对,写一个函数,然后传值进去, function Person(name,age){ this.name = name; this.age ...