这篇文章描述 ASP.NET Web API 如何将 HTTP 请求路由到特定的操作在控制器上。

有关路由的高级别概述,请参见ASP.NET Web API 的路由.

本文着眼于路由进程的详细信息。如果你创建一个 Web API 项目并发现一些请求不要路由你期望的方式,希望这篇文章将帮助。

路由具有三个主要阶段 ︰

  1. 匹配的 URI 到工艺路线模板。
  2. 选择一个控制器。
  3. 选择操作。

您可以用您自己的自定义行为替换一些零件的过程。在本文中,我描述的默认行为。最后,我注意到的地方,在那里你可以自定义的行为。

工艺路线模板

工艺路线模板看起来类似于 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类提供默认实现。此类使用一种简单的算法 ︰

  1. 在路由字典键"控制器"中查找。
  2. 采取此键的值和追加字符串"控制器",得到控制器的类型名称。
  3. 寻找与此类型名称的 Web API 控制器。

例如,如果路由字典包含键-值对"控制器"="产品",然后是控制器的类型是"ProductsController"。如果没有匹配的类型或多个匹配项,框架向客户端返回错误。

步骤 3, DefaultHttpControllerSelector使用IHttpControllerTypeResolver接口获取 Web API 控制器类型的列表。IHttpControllerTypeResolver的默认实现返回所有的公共类的 (a) 执行IHttpController,(b) 是不抽象,和 (c) 有一个名称,在"控制器"中结束。

选择动作

选择控制器后, 框架通过调用IHttpActionSelector.SelectAction方法将选择的行动。此方法采用HttpControllerContext并返回HttpActionDescriptor.

ApiControllerActionSelector类提供默认实现。若要选择一个动作,它看起来在以下 ︰

  • 请求的 HTTP 方法。
  • 在工艺路线模板中,如果存在"的行动 {}"占位符。
  • 在控制器上的操作的参数。

选择算法之前,我们需要了解一些控制器操作的东西。

在控制器上的方法被视为"行动"?当选择某个操作,框架只是看看公共实例方法的控制器上。此外,它排除了"特别的名字"方法 (构造函数、 事件、 运算符重载,等等),和从继承的方法ApiController类。

的 HTTP 方法。框架只选择匹配的要求,确定如下的 HTTP 方法的行为 ︰

  1. 您可以使用属性指定的 HTTP 方法 ︰ AcceptVerbs、 HttpDelete公共、 HttpHead、 HttpOptions、 HttpPatch、 HttpPostHttpPut.
  2. 否则,如果控制器方法的名称以"Get"、"开机自检"、"放"、"删除"、"头"、"选项"或"修补程序"开头,然后由公约行动支持的 HTTP 方法。
  3. 如果以上都不是,该方法支持邮政。

参数绑定。参数绑定是如何 Web API 创建参数的值。参数绑定的默认规则是这样的 ︰

  • 简单类型是采取从 URI。
  • 复杂类型是取自请求正文。

简单类型包括所有的.NET 框架基元类型,加上日期时间十进制、 Guid字符串时间跨度。为每个操作,顶多一个参数可以读取请求正文。

它是可以重写默认绑定规则。请参见WebAPI 参数绑定引擎盖下.

与这种背景下,这里是行动选择算法。

  1. 在匹配的 HTTP 请求方法的控制器上创建的所有操作的列表。
  2. 如果路由字典有的"操作"项,删除其名称与此值不匹配的操作。
  3. 尝试匹配到的 URI,操作参数,如下所示 ︰
    1. 为每个操作,得到是一个简单的类型,其中绑定从 URI 获取参数的参数的列表。排除的可选参数。
    2. 从该列表中,试着找到适合每个参数的名称,或者路由字典或 URI 的查询字符串中。匹配项是区分大小写,并不依赖于参数顺序。
    3. 选择列表中的每个参数在 URI 匹配操作。
    4. 如果更多这一行动符合这些标准,挑选一个有大多数的参数匹配。
  4. 忽略[侵权]属性的行动。

步骤 #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、 GetByIdFindProductsByName。路由字典不包含"行动"的条目,所以我们不需要匹配的操作名称。

接下来,我们尝试匹配参数名称的操作,只看得到的行动。

行动 匹配的参数
GetAll 没有一个
GetById ""id
FindProductsByName "名称"

请注意,不是GetById版本参数,因为它是一个可选的参数。

GetAll方法匹配琐细。GetById方法也相匹配,因为路由字典包含"id"。FindProductsByName方法不匹配。

GetById方法赢了,因为它与一个参数,与GetAll没有参数相匹配。用下面的参数值调用该方法 ︰

  • id = 1
  • 版本= 1.5

请注意,即使在选择算法不使用版本,参数的值来自 URI 的查询字符串。

扩展点

Web API 的某些部件中的路由选择进程提供了扩展点。

为任何这些接口提供自己的实现,请使用HttpConfiguration对象上的服务集合 ︰

2.2WebApi路由在Action上的更多相关文章

  1. 爱上MVC3~在控制器或Action上动态设定模板页(Layout)

    回到目录 很多境况下,我们需要设置自己模块的layout,即它的布局页面,在MVC2中叫它模板页面,你可以在return view方法时设置它,当然,这不是一种好方法,因为我不想每个action都去设 ...

  2. WebApi:路由和Action选择

      译自:http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection   ...

  3. struts2,action上传文件

    通过servlet实现文件上传,可以用用servlet接受到request的值的话:主要是这句话 List<?> items = upload.parseRequest(request); ...

  4. vue-router 获得上一级路由以及返回上一级路由的方法

    if (this.$store.state.previousRouter.name) { this.$router.push({name: this.$store.state.previousRout ...

  5. 首页重定位到mian.action上

    <body onload="top.location.href='<%=request.getContextPath()%>/main.action';">

  6. asp.net core的授权过滤器中获取action上的Attribute

    var action = context.ActionDescriptor as ControllerActionDescriptor; var permission = action.MethodI ...

  7. MVC POST在ACTION上进行多个模型的数据绑定

    首先声明,接下来的东西并不符合本人认同的严谨的MVC模式. 用MVC做项目的过程中,越来越多的用到不严谨的MVC编程. 比如,在"cshtml"文件中写: @Html.Raw(DB ...

  8. 工作总结 [ActionName("ss123")] 更改路由中Action名称 获取或设置操作的名称

  9. 解读ASP.NET 5 & MVC6系列(11):Routing路由

    新版Routing功能介绍 在ASP.NET 5和MVC6中,Routing功能被全部重写了,虽然用法有些类似,但和之前的Routing原理完全不太一样了,该Routing框架不仅可以支持MVC和We ...

随机推荐

  1. C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 角色成员功能的改进支持公司加入到角色

    我们公司有1万多个网点,每个网点都可以看成是一个公司,公司对不同的网点有不同的策略,商业逻辑,每个网点的人员也都是在不断变化,全国有接近10万从业人员,当我们设计好业务逻辑程序后,不可能因为这些人员的 ...

  2. web前端开发最佳实践笔记

    一.文章开篇 由于最近也比较忙,一方面是忙着公司的事情,另外一方面也是忙着看书和学习,所以没有时间来和大家一起分享知识,现在好了,终于回归博客园的大家庭了,今天我打算来分享一下关于<web前端开 ...

  3. ionic路由传值

    ionic路由传值 app.js ===================================== //新建工作任务.state(‘app.newTask’, angularAMD.rout ...

  4. safehandle 和析构函数

    safehandle 是一种析构机制,她和析构函数有什么分别. 首先要理解析构函数.析构函数在.net中是没有顺序的,因此你不能假定另一个对象的析构函数在你之后运行,哪怕它是你的成员!如果你的成员也有 ...

  5. 有border和没有border是两回事

    id="box"设立border的话,里边的p样式为display:block;margin-top:20px; 如果你把margin-top的值不断添加的话,会显示为距borde ...

  6. 使用PhpDocumentor生成文档

    一,网站根目录执行 $ composer require --dev phpdocumentor/phpdocumentor 二,进入vendor/bin/目录执行 $phpdoc -d D:\ser ...

  7. 解决:sudo: 无法解析主机:dinphy-500-310cn: 连接超时

    出现这种问题是hosts文件没有配置好所导致的,linux无法解析到您的主机地址,解决方案如下: sudo vim /etc/hosts 其中vim是你的文本编辑器的命令,你如果电脑中没有vim,用g ...

  8. android开发之背景音乐与音效

    android开发之背景音乐与音效 一:添加背景音乐(MediaPlayer) MediaPlayer class can be used to control playback of audio/v ...

  9. 【BZOJ-3243】向量内积 随机化 + 矩阵

    3243: [Noi2013]向量内积 Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 1249  Solved:  ...

  10. 移动端webUI框架(HTML5手机框架)

    淘宝SUI Mobile框架 官网地址:http://m.sui.taobao.org/ SUI Mobile 是一套基于 Framework7 开发的UI库.它非常轻量.精美,只需要引入我们的CDN ...