当前位置: 首页 > 编程日记 > 正文

Web API路由和动作选择

前言

本文描述ASP.NET Web API如何把一个HTTP请求路由到控制器的一个特定的Action上。关于路由的总体概述可以参见上一篇教程 http://www.cnblogs.com/aehyok/p/3442051.html。这篇文章主要来学习路由过程的细节。如果你创建了一个Web API项目,发现有一些请求没有按照你期望的方式被路由,希望这篇文章将对你有所帮助。

本文主要分为三个阶段:

1.匹配URI到一个Route Template。

2.选择一个Controller。

3.选择一个Action。

你可以用自己的自定义行为来替换这一过程中的某些部分。在本文中,我将来描述默认的行为。在文章结尾,我会注明可以在什么地方自定义行为。

Route Templates

路由模版看上去类似于一个URI路径,但它可以具有占位符,并用花括号来指示:

"api/{controller}/public/{category}/{id}"

当创建一个路由的时候,你可以为某些或所有占位符提供默认值:

defaults: new { category = "all" }

你也可以提供约束,它限制URI片段如何与占位符匹配:

constraints: new { id = @"\d+" }   // Only matches if "id" is one or more digits.

上面语句是通过正则表达式来限制片段的取值,上面的注释说明 id片段只匹配一个或多个数字,因此URI中的id片段必须是数字才能与这个路由进行匹配。

这个框架试图把URI路径中的片段与这个模板进行匹配。模板中的文字必须严格匹配。一个占位符可以匹配任何值,除非你指定了约束。这个框架不会匹配URI另外的部分,例如主机名或者一个查询字符串。这个框架会选择路由表中第一个匹配的路由。

这里有两个特殊的占位符:“{controller}”和“{action}”。

  • “{controller}”提供控制器名。
  • “{action}”提供动作名。在Web API中,通常的约定是忽略“{action}”的。

Defaults(默认值)

如果你提供默认值,那么这个路由将匹配缺少这些片段的URI。例如:

复制代码
routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{category}", defaults: new { category = "all" } 
);
复制代码

这个URI“http://localhost/api/products”与这个路由是匹配的。“{category}”片段被赋成了默认值“all”。

Route Dictionary(路由字典)

如果这个框架发现了一个匹配的URI,它会创建包含每个占位符值的一个字典。这个键值是不带花括号的的占位符名称。这个值取自于URI路径或者是默认值中的。这个字段被存在IHttpRouteData对象中。在匹配路由阶段,这个特殊的"{controller}" and "{action}"占位符的处理和其他占位符是一样的。它们用另外的值被简单的存储在字典中。

在默认值中可以使用特殊的RouteParameter.Optional值。如果一个占位符被赋予了这个值,那么这个值将不会被添加到路由字典中,例如:

复制代码
routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{category}/{id}", defaults: new { category = "all", id = RouteParameter.Optional } 
);
复制代码

对于URI路径“api/products”,路由字典将含有:controller:"products"、category:"all"。

然而,对于“api/products/toys/123”,路由字典将含有:controller:"products"、category:"toys"、id:"123"。

这个默认值也可以包含未出现在路由模板中的值。若这条路由匹配,则该值会被存储在路由字典中。例如:

复制代码
routes.MapHttpRoute( name: "Root", routeTemplate: "api/root/{id}", defaults: new { controller = "customers", id = RouteParameter.Optional } 
);
复制代码

如果URI路径是“api/root/8”,字典将含有两个值:controller:“customers”,id:"8"。

Selecting a Controller

控制器选择是由IHttpControllerSelector.SelectController方法来处理的。这个方法以HttpRequestMessage实例为参数,并返回HttpControllerDescriptor

其默认实现是由DefaultHttpControllerSelector类提供的。这个类使用了一种很直接的算法:

1.查找路由字典的“controller”键。

2.取得这个键的值,并附加字符串“Controller”,以得到控制器的类型名。

3.用这个类型名查找Web API控制器。

例如,如果路由字典中的键-值对为“controller”=“products”,那么控制器类型便为“ProductsController”。如果没有匹配类型,或有多个匹配,这个框架会给客户端返回一条错误。

对于步骤3,DefaultHttpControllerSelector使用IHttpControllerTypeResolver接口以获得Web API控制器类型的列表。 IHttpControllerTypeResolver的默认实现会返回所有符合以下条件的public类:

a:实现IHttpController的类。

b:是非抽象类。

c:名称以“Controller”结尾的类。

Action Selection

选择了控制器之后,这个框架会通过调用IHttpActionSelector.SelectAction方法来选择动作。这个方法以HttpControllerContext为参数,并返回HttpActionDescriptor

这个默认实现是由ApiControllerActionSelector类提供的。为了选择一个动作,会查找以下方面:

1.HTTP请求的方法。

2.这个路由模板中的“action”占位符。

3.控制器中动作的参数。

在查找选择算法之前,我们需要理解控制器动作的一些事情。

  控制器中的哪些方法被看成为是“动作”?当选择一个动作时,这个框架只考察控制器的public实例方法。而且,它会排除特殊名称的方法(构造器、事件、操作符、重载等等),以及集成自ApiController的类方法。

HTTP Methods

这个框架只会选择与请求的HTTP方法匹配的动作,确定如下:

1.你可以用注解属性AcceptVerbs、HttpDelete、HttpGet、HttpHead、HttpOptions、HttpPatch、HttpPost、或HttpPut来指定HTTP方法。

2.否则,如果控制器方法名称以“Get”、“Post”、“Put”、“Delete”、“Head”、“Options”、或“Patch”开头,那么根据这个约定,该Action将支持相应的HTTP方法。

3.如果以上都不是,那么这个方法将支持Post。

Parameter Bindings.

参数绑定是指Web API如何创建参数值。以下是参数绑定的默认规则:1.简单类型取自URI。2.复杂类型取自请求正文。

简单类型包括所有“.NET框架简单类型”,另外还有,DateTime、Decimal、Guid、String和TimeSpan。对于每一个动作,最多只有一个参数可以读取请求正文。

它也可以重写这种默认的绑定规则。See WebAPI Parameter binding under the hood。

在这种背景下,动作选择算法如下:

1.创建该控制器中与HTTP请求方法匹配的所有动作的列表。

2.如果路由字典有“action”条目,移除与该条目值不匹配的动作。

3.试图将动作参数与该URI匹配,如下:

a:针对每个动作,获得简单类型的参数列表,这是绑定得到URI参数的地方。该列表不包括可选参数。

b:从这个列表中,试着在路由字典或是在URI查询字符串中,找到每个参数的匹配。匹配是与大小写无关的,且与参数顺序无关。

c:选择这样的一个action,在列表中的每个参数在URI中有一个匹配。

d:如果满足这些条件的动作不止一个,选用参数匹配最多的一个。

4.忽略用[NonAction]注解属性标注的动作。

第3步可能会让人困扰。其基本思想是,可以从URI、或请求体、或一个自定义绑定来获取参数值。对于来自URI的参数,我们希望确保URI在其路径(通过路由字典)或查询字符串中实际包含了一个用于此参数的值。

例如,考虑以下动作:

public void Get(int id)

其id参数绑定到URI。因此,这个动作只能匹配在路由字典或查询字符串中包含了“id”值的URI。

可选参数是一个例外,因为它们是可选的。对于可选参数,如果绑定不能通过URI获取它的值,是没关系的。

复杂类型是另一种原因的例外。一个复杂类型只能通过自定义绑定来绑定到URI。但是在这种情况下,这个框架不能提前知道是否这个参数被绑定到一个特殊的URI。为了查明情况,这个框架需要调用这个绑定。选择算法的目的是在调用绑定之前根据静态描述来选择一个动作。因此,复杂类型是属于匹配算法之外的。

动作选择之后,会调用所有参数绑定。

Summary:

1.动作必须匹配请求的HTTP方法。

2.动作名必须匹配路由字典中的“action”条目,如果有。

3.对于动作的各个参数,如果参数取自URI,那么该参数名必须在路由字典或URI查询字符串中能够被找到。(可选参数和复杂类型除外)。

4.试图匹配最多数目的参数。最佳匹配可能是一个无参数的方法。

Extended Example

看如下路由:

复制代码
复制代码
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 } 
);
复制代码
复制代码

再看如下Contoller下的内容:

复制代码
复制代码
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请求:

http://localhost:34701/api/products/1?version=1.5&details=1

路由匹配:

该URI与名为“DefaultApi”路由匹配。路由字典包含以下条目:controller:"products",id:"1"。该路由字典并未包含查询字符串参数“version”和“details”,但这些将在动作选择期间考虑。

控制器选择:

根据路由字典中的“controller”条目,控制器类型是ProductsController。

动作选择:

这个HTTP请求是一个GET请求。支持Get的控制器动作是GetALL、GetById、FindProductsByName。这个路由字典不包含”action“条目,因此不需要匹配动作名称。

下一步,会试图匹配这些动作的参数名,只考查GET动作。

注意,不会考虑GetById的version参数,因为它是一个可选参数。

GetAll方法非常匹配。GetById方法也匹配,因为路由字典包含了“id”。FindProductsByName方法不匹配。

GetById方法是赢家,因为它匹配了一个参数,而GetAll无参数。该方法将以以下参数值被调用:id=1,version=1.5

注意,虽然version未被用于选择算法,但该参数值会取自URI查询字符串。

Extension Points

Web API为路由过程的某些部分提供了扩展点。

要为以上任一接口提供自己的实现,可使用HttpConfiguration对象的Services集合:

var config = GlobalConfiguration.Configuration;
config.Services.Replace(typeof(IHttpControllerSelector), new MyControllerSelector(config));

总结

相关文章:

希望和等待:目标,欲望和意志

意志是盲目的。 欲望是不能消灭的&#xff0c;只能代替。 高人云&#xff0c;人生最重要的是什么&#xff1f;是目标。哲人言&#xff0c;人生无非希望和等待而已。 人的信息系统是任务为导向的&#xff0c;所有的人都有目标&#xff0c;不过自觉不自觉&#xff0c;大小&#x…

c4d+ps打造抽象NFT加密艺术 Create Abstract NFT Crypto Art with Cinema 4D + Photoshop

c4dps打造抽象NFT加密艺术 Create Abstract NFT Crypto Art with C4D PS c4dps打造抽象NFT加密艺术 Create Abstract NFT Crypto Art with C4D PS c4dps打造抽象NFT加密艺术 Create Abstract NFT Crypto Art with C4D PS c4dps打造抽象NFT加密艺术 Create Abstract NFT Cryp…

vb打开ftp服务器文件路径,VB上传指定文件到FTP指定目录。。

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼目前用如下代码能够实现上传&#xff0c;但是不能上传到指定目录去。。怎么改变&#xff1f;Option ExplicitPrivate Const INTERNET_OPEN_TYPE_DIRECT 1Private Const scuseragent "vb wininet"Private Const INTERNE…

firefox+linux+nginx搭建server与client通过证书双向认证环境

项目中需要搭建一个server和client基于证书的双向认证环境。由我来做&#xff0c;我也不会。 经过一晚上的研究&#xff0c;基本摸清了&#xff08;知其然不知其所以然&#xff09;。做下笔记。 基本环境&#xff1a; 1.安装nginx。 2.安装openssl。 生成证书&#xff1a; 首先…

编写高性能Java代码的最佳实践

编写高性能Java代码的最佳实践 摘要&#xff1a;本文首先介绍了负载测试、基于APM工具的应用程序和服务器监控&#xff0c;随后介绍了编写高性能Java代码的一些最佳实践。最后研究了JVM特定的调优技巧、数据库端的优化和架构方面的调整。以下是译文。 介绍 在这篇文章中&…

Exchange 2013 OWA搜索邮件失败问题处理

Exchange 2013 OWA搜索邮件失败问题处理问题&#xff1a;接到用户反馈&#xff0c;exchange 2013 owa搜索邮件失败&#xff0c;提示“您的搜索未返回任何结果“&#xff0c;如下图&#xff0c;但是outlook搜索正常。打开EMS命令行工具&#xff0c;get-mailboxdatabasecopystatu…

PAT_B_1027 打印沙漏

题目描述&#xff1a; 本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”&#xff0c;要求按下列格式打印************ ***** 所谓“沙漏形状”&#xff0c;是指每行输出奇数个符号&#xff1b;各行符号中心对齐&#xff1b;相邻两行符号数差2&#xff1b;符…

3dmax2021入门学习教程

3dmax2021入门学习教程 MP4 | h264&#xff0c;1280x720 |语言&#xff1a;英语中文字幕&#xff08;根据原英文字幕机译&#xff09;原英文字幕 | 4h 23m | 3.55 GB 含课程素材工程文件 云桥网络 平台获取素材 你将学到什么 3DS MAX中的样条线和多边形建模 纹理、照明和渲…

关于HTML代码的转义

笔记&#xff1a; 1.在通过jsonp方式传输HTML代码的时候&#xff0c;为了防止代码中的一些字符影响json的语法&#xff0c;需要对HTML代码进行转义。 2.转义的时候可以只转义特殊字符&#xff08;引号之类的&#xff09;&#xff0c;也可以把所有字符&#xff08;中文&#xff…

php ajax替换数据,如何用ajax替换php函数

我是这里的 AJAX 新手。ajax的动作执行后如何替换初始的php函数&#xff1f;我发现执行操作后页面不会刷新。这是代码&#xff1a;javascriptfunction set_ddm(another_data) {var result $.ajax({url: ../display/ea_form_header.php,type: POST,data: {action: set_ddm,Data…

2022-2028年中国输送胶管行业市场全景调查及投资前景趋势报告

【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新&#xff08;交付时间约3个工作日&#xff09; 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国输送胶管行业市场行业相关概述、中国输送胶管行业市场行业运行环境、分析了中国输送胶管行…

CGIC简明教程(转摘)

CGIC简明教程 本系列的目的是演示如何使用C语言的CGI库“CGIC”完成Web开发的各种要求。&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#xff0a;&#…

conflicts with existing, non-compatible bean definition of same name and class

Annotation-specified bean name xxxxxImpl for bean class [cn.abc.dao.service.xxxxxImpl] conflicts with existing, non-compatible bean definition of same name and class [cn.abc.dao.service.dev.xxxxxIImpl] 编译没问题&#xff0c;运行就报错了。 一查原来发现在dao…

Tree 使用方式

Traditional Ways of Tree Traversal This page contains examples of some “standard” traversal algorithms (ones that can be found in most textbooks). All examples perform pre-order tree traversal on a general rooted tree. “Algorithms, Data Structures and P…

网站更换服务器ip地教程,由于服务器更换IP地址,服务器不更换。需要如何操作使网站正常运行呢?,POSCMS,CodeIgniter技术文档,PHP开发文档,迅睿CMS框架官方教程...

多文件Files内容详情中(show.html) 模板中调用方法是&#xff1a;{loop $字段名 $i $c} 序号: {$i} 标题&#xff1a;{$c.title} 描述&#xff1a;{$c.description} 文件原始地址&#xff1a;{dr_get_file($c.file)} 文件的下载地址&#xff1a;{dr_down_file($c.file)} 图片缩…

3ds Max V-Ray5 完整指南大师班视频教程

3ds Max V-Ray5 完整指南大师班视频教程 时长15小时 包括项目文件 1920X1080 MP4 语言&#xff1a;英语中文字幕&#xff08;机译&#xff09; 标题&#xff1a;Gumroad–V-Ray 5 Masterclass:您的3ds Max V-Ray完整指南 大小&#xff1a;41.8G 共八大章 88小节课程 信息&am…

2022-2028年中国氢化丁晴橡胶行业市场研究及前瞻分析报告

【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新&#xff08;交付时间约3个工作日&#xff09; 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国氢化丁晴橡胶电商行业市场行业相关概述、中国氢化丁晴橡胶电商行业市场行业运行环境、分析…

配置Exchange OWA和Sharepoint网站单点登录

配置Exchange OWA和Sharepoint网站单点登录如果我们在组织中已经部署完成了Lync、Exchange以及Sharepoint&#xff0c;那么我们会发现这三套系统在通过域账户登录计算机时&#xff0c;如果本机有安装Outlook和Lync&#xff0c;那么在登录Lync或启动Outlook的时候就会自动使用当…

BigTable

转载于:https://www.cnblogs.com/fanweisheng/p/11250529.html

Blender2.9全流程创建逼真未来科幻蝙蝠汽车视频教程

Blender2.9全流程创建逼真未来科幻蝙蝠汽车视频教程 MP4 |视频&#xff1a;h264&#xff0c;1280720 |音频&#xff1a;AAC&#xff0c;44.1 KHz&#xff0c;2通道 含课程工程素材 体裁&#xff1a;在线学习|语言&#xff1a;英语中文字幕&#xff08;根据原英文字幕机译更准…

微服务项目用了几台服务器,微服务部署运维

docker介绍&#xff0c;及作用就是类似VM虚拟机一样的虚拟容器技术。docker 可以帮我们把所需要的应用打包容器&#xff0c; 每一个容器都相互独立的&#xff0c;而且容器占用内存小&#xff0c;启动和管理的速度非常快。比如 之前我们使用linux 虚拟机&#xff0c;如果要用mys…

JAVA用最简单的方法来构建一个高可用的服务端,提升系统可用性

一、什么是提升系统的高可用性 JAVA服务端&#xff0c;顾名思义就是23体验网为用户提供服务的。停工时间&#xff0c;就是不能向用户提供服务的时间。高可用&#xff0c;就是系统具有高度可用性&#xff0c;尽量减少停工时间。如何用最简单的方法来搭建一个高效率可用的服务端…

jQuery学习笔记一

2019独角兽企业重金招聘Python工程师标准>>> 1、使用attr()方法控制元素的属性 attr()方法的作用是设置或者返回元素的属性&#xff0c;其中attr(属性名)格式是获取元素属性名的值&#xff0c;attr(属性名&#xff0c;属性值)格式则是设置元素属性名的值。 2、操作元…

关于60枚一分两分五分硬币凑成一块钱的解决方法

关于60枚一分两分五分硬币凑成一块钱的解决方法 一.强行三重for循环 #include<stdio.h> int main() {int a, b, c;for (a 1; a < 60; a){for (b 1; b < 60; b){for (c 1; c < 60; c){if (100 5 * c 2 * b a && 60 a b c){printf("%d %d…

hbase RPCServer源码分析

前置知识&#xff1a; java&#xff0c;nio&#xff0c;多线程 看了几天的源码&#xff0c;写一些自己心得&#xff0c;若有错误请指出。 RPCServer的作用&#xff1a;负责创建listener&#xff0c;reader&#xff0c;responser&#xff0c;handler来处理client端的请求。 RPCS…

Maya创建科幻3D动画循环场景视频教程

Maya创建科幻3D动画循环场景视频教程 Skillshare – Create a Sci-Fi 3D Animation Loop in Autodesk Maya 持续时间3h 27m 包括项目文件 1280X720 Mkv 语言&#xff1a;英语中文字幕&#xff08;根据原英文字幕机译更准确&#xff09;原英文字幕 大小解压后 3.05G 共20小节课…

2022-2028年中国氢化丁腈橡胶行业市场深度分析及投资规模预测报告

【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新&#xff08;交付时间约3个工作日&#xff09; 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国氢化丁腈橡胶行业市场行业相关概述、中国氢化丁腈橡胶行业市场行业运行环境、分析了中国氢…

js中的json对象和字符串之间的转化

字符串转对象(strJSON代表json字符串) var obj eval(strJSON); var obj strJSON.parseJSON(); var obj JSON.parse(strJSON)&#xff1b; json对象转字符串(obj代表json对象) var str obj.toJSONString(); var str JSON.stringify(obj) 运用时候需要除了eval()以外需要jso…

三种方式实现分布式锁

通过以上过程你可以发现锁的获取是按照创建时间来的,谁先来争取锁谁就先获得锁,因此它实现的是公平锁。答案是不能,以Synchronized关键字为例,Synchronized关键字无论是在偏向锁、轻量级锁还是重量级锁状态都不能实现这点,如重量级锁,重量级锁是靠系统底层的互斥量Mutex实现的,也就是说每个节点(服务器)所使用的互斥量是分开的,节点A的互斥量是无法锁住节点B的线程访问临界区,因此Synchronized关键字只能保证单服务器内的JVM进程的不同线程同步,是不能用做分布式环境中来保证线程同步。

超级挂载 实现过程-代码

公司产品是给机顶盒或者电视做的&#xff0c;玩的就是大型游戏&#xff0c;一个游戏常常能有G级别的数据包&#xff0c;于是产生一个需求&#xff0c;将游戏的数据包存放在外置sdcard上&#xff0c;用户差一个32G的卡能随便玩游戏&#xff0c;不占用设备自身的存储容量&#xf…