一、WebApi路由机制是什么?

  路由机制通俗点来说:其实就是WebApi框架将用户在浏览器中输入的Url地址和路由表中的路由进行匹配,并根据最终匹配的路由去寻找并匹配相应的Controller和Action并执行的一个过程。

从WebApi框架接收到来自外部环境的接口调用请求到指定接口的执行大概需要以下的匹配过程:1、匹配URL路由 2、Controller匹配 3、Action匹配

下面我么分别对这几个流程进行详细说明。

二、匹配URL路由

  WebApi框架接收到来自外部的接口请求后,首先将路由表中的路由一条一条和Url地址进行匹配,一旦匹配上则不再继续往下匹配,如果匹配完了所有路由都未匹配上,则会报404错误。

如果成功匹配上指定路由,则框架根据路由的Url模板中指定的Controller的所在位置以及Action的所在位置从用户请求的Url中提取出将要调用的Controller的名称以及Action的名称,当然要被调用的Controller名或者Action名也可能不是从用户发起的接口调用请求Url中获得的,因为WebApi中在进行路由配置时提供了参数默认值的配置,也就是说Controller名或者Action名可能来源于路由配置时的默认值。

该流程结束后:WebApi框架将会从用户请求的接口调用URL中提取出用户想调用的接口所对应的Controller 、Action 、以及用户传给指定Action的参数(即路由数据)等等,

这些数据存储在了一个字典集合中,这个路由数据字典我们可以在Action方法中通过如下方式获得:

 IHttpRouteData routeData = Request.GetRouteData();
IDictionary<string, object> routeDataValues = routeData.Values;

  这里需要澄清的几点的是:

1、URL未匹配上任何路由 和  匹配上了路由但是未找到相应的Controller和Action 是两个不同的概念,IIS对这两种情况的响应是不一样的。

URL未匹配上路由:

  如果用户请求的接口的地址不能和路由表中的所有路由相匹配,IIS将直接报告404错误。

匹配上了路由但未找到相应Controller或Action:

如果匹配上了路由但是未找到响应的Controller或Action,那么将报类似如下错误:

  MessageDetail节点详细描述了是 Controller未找到还是 Action未找到。

2、由于路由表中可以配置一条或者多条路由,并且WebApi框架在匹配成功一条路由后将不再继续往下匹配,也就是说即使此时后面还有路由可以

和当前请求匹配也不会被匹配到,所以请务必注意每条路由的配置顺序,否则可能造成意想不到的结果。

如:

 public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "TestRoute",
routeTemplate: "{controller}/{action}",
defaults: new { action = "Index" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
); }

假设我们此时代码中包含如下控制器和Action:

 public class ValuesController : ApiController
{
public string Get()
{
return "value";
}
[HttpGet]
public object QueryValues(int index)
{
string[] strs = new string[] { "张三", "李四" };
if (index < || index >= strs.Length)
{
return JsonConvert.SerializeObject(strs);
}
return strs[index];
}
}

我们在浏览器中输入:http://localhost:16982/api/Values,会发现总是匹配到的是TestRoute这个路由,实际上我们只是想访问Values中的无参数的Get方法。

事实上,解决这个问题只需要将TestRoute路由的配置放到DefaultApi路由的后面即可。

三、Controller匹配

经过路由匹配后,框架已经从用户请求的Url中提取到需要访问的Controller名、Action名、以及在路由模板中定义的参数所对应的值等等,此时WebApi框架从路由数据字典中获取出键为:controller的值,在这个值的基础上去找类型名为  Controller名+Controller 结尾的类,此时如果找到相应名称的Controller类,则Controller匹配成功,但此时仅仅是Controller匹配成功,最终接口能否成功调用还需取决于下一个步骤中的Action匹配。

  Controller的匹配主要由接口:IHttpControllerSelector.SelectController方法来处理的,这个是WebApi框架定义的接口,定义如下:

 public interface IHttpControllerSelector
{
// Methods
IDictionary<string, HttpControllerDescriptor> GetControllerMapping();
HttpControllerDescriptor SelectController(HttpRequestMessage request);
}

  WebApi框架对控制器的匹配进行了默认的实现,类名叫做:DefaultHttpControllerSelector,这个类默认实现了查找Controller的过程,在DefaultHttpControllerSelector内部通过

IHttpControllerTypeResolver接口加载出所有的满足条件的控制器类型,能被加载并查找的控制器类型必须满足以下条件:

1、类必须是实现了IHttpController接口

2、必须是public

3、不能是abstract类

4、类名必须以Controller结尾

最终,从这些列表中找出名称和路由数据中的Controller名同名的Controller类,并创建该类的实例对象。

当然如果我们需要有自己的控制器匹配的逻辑,我们也可以对其进行配置,通过在:/App_Start/WebApiConfig.cs类中进行配置,配置方式如下所示:

     public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// 这里我们配置成使用自己写的匹配控制器的逻辑
     GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new MyHttpControllerSelectory(GlobalConfiguration.Configuration));
}
}

虽然WebApi框架给我们提供了匹配控制器行为的扩展点,但是微软的默认实现类DefaultHttpControllerSelector基本上可以满足大多数场景了。

四、Action匹配

   路由机制找到了将要被调用的Controller类后,接下来就是在当前已经被匹配成功的控制器类下找一个合适的Action方法,并对其调用了,Action的具体匹配流程如下:

1、根据用户调用接口时的请求方式(GET/POST/DELETE/PUT/Head等等)从已经匹配的控制器类中查找是用于该种请求方式的Action方法,通过该轮匹配可能会匹配出多个符合条件的Action方法。

2、如果路由数据字典中包含键为:action的值,那么表示Action的名称必须和该字典中的actionName相一致,也就是说只有Action方法的名称和路由数据字典中的action名匹配的才算再次步骤匹配。(该步骤不一定是必须执行的,取决于被匹配的路由中是否有指定action占位符)

3、最后一步就是action的参数绑定了,action中的各个参数的值要么来源于路由Url模板中定义好的参数在Url中提取到的值,要么来源于QueryString(也就是?后面的参数值),当然这些说的只是.NET中的原生类型(包括:int/double/DateTime/TimeSpan/Guid等等)的绑定。并不包括自定义的复杂类型(如模型类),其实复杂类型的参数值的绑定默认实现方式是从请求报文提中获得的。

Action的选择由接口IHttpActionSelector.SelectAction()方法进行实现,WebApi框架对Action的匹配进行了默认的实现,默认实现类名为:ApiControllerActionSelector,

IHttpActionSelector接口定义如下:

 public interface IHttpActionSelector
{
// Methods
ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor);
HttpActionDescriptor SelectAction(HttpControllerContext controllerContext);
}

  需要说明的是:能作为Action被执行的方法必须满足以下几点:

1、必须是public修饰的方法

2、未被[NonAction]特性修饰的方法

3、不是从ApiController类中继承过来的方法

4、控制器的构造函数,等等也不会被匹配。

Action的匹配我们也可以实现自定义匹配规则,和上面提到的自定义Controller匹配规则的配置方式类似,如下:

 public static void Register(HttpConfiguration config)
{
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionSelector), new MyApiControllerActionSelector()); }

  本文主要讲述了WebApi框架如何将来自用户的接口调用请求映射到具体的Controller和Action,并对其进行执行的过程,最容易让人困惑的部分或许还是Action的选择部分,

后续我们将继续讨论关于Action选择部分的具体细节以及参数绑定过程。

 

WebApi-路由机制的更多相关文章

  1. C#进阶系列——WebApi 路由机制剖析:你准备好了吗?

    前言:从MVC到WebApi,路由机制一直是伴随着这些技术的一个重要组成部分. 它可以很简单:如果你仅仅只需要会用一些简单的路由,如/Home/Index,那么你只需要配置一个默认路由就能简单搞定: ...

  2. 【C#】 WebApi 路由机制剖析

    C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转自:https://blog.csdn.net/wulex/article/details/71601478 2017年05月11日 10 ...

  3. C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转载https://www.cnblogs.com/landeanfen/p/5501490.html

    阅读目录 一.MVC和WebApi路由机制比较 1.MVC里面的路由 2.WebApi里面的路由 二.WebApi路由基础 1.默认路由 2.自定义路由 3.路由原理 三.WebApi路由过程 1.根 ...

  4. WebApi 路由机制剖析

    阅读目录 一.MVC和WebApi路由机制比较 1.MVC里面的路由 2.WebApi里面的路由 二.WebApi路由基础 1.默认路由 2.自定义路由 3.路由原理 三.WebApi路由过程 1.根 ...

  5. WebApi路由机制详解

    随着前后端分离的大热,WebApi在项目中的作用也是越来越重要,由于公司的原因我之前一直没有机会参与前后端分离的项目,但WebApi还是要学的呀,因为这东西确实很有用,可单独部署.与前端和App交互都 ...

  6. MVC和WebApi路由机制比较

    1.MVC使用的路由 在MVC中,默认路由机制是通过解析url路径来匹配Action.比如:/User/GetList,这个url就表示匹配User控制器下的GetList方法,这是MVC路由的默认解 ...

  7. WebApi-1 与MVC路由机制比较

    在MVC里面,默认路由机制是通过url路径去匹配对应的action方法 public class RouteConfig { public static void RegisterRoutes(Rou ...

  8. Web Api 的 路由机制

    ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动设备)的 HTTP 服务. ASP.NET Web API 是一种用于在 .NET Framework 上构 ...

  9. Linux mips64r2 PCI中断路由机制分析

    Linux mips64r2 PCI中断路由机制分析 本文主要分析mips64r2 PCI设备中断路由原理和irq号分配实现方法,并尝试回答如下问题: PCI设备驱动中断注册(request_irq) ...

  10. 走进AngularJs(八) ng的路由机制

    在谈路由机制前有必要先提一下现在比较流行的单页面应用,就是所谓的single page APP.为了实现无刷新的视图切换,我们通常会用ajax请求从后台取数据,然后套上HTML模板渲染在页面上,然而a ...

随机推荐

  1. PHP 相对完整的分页

    效果链接http://love.bjxxw.com/oejiaoyou/pubu/zhaopian.php php 分页 <?php /* * * * 说明 吉海波 2015/9/17 * $p ...

  2. bootstrap 模态框(modal)插件使用

    今天用户登陆时,在原网页上弹出新登陆窗口,发现使用的是modal插件,记录下该插件的使用方法,手写强化下. 首先,模态框(modal)是覆盖在父窗体上的子窗体,目的是显示来自一个单独的源的内容,可以在 ...

  3. java基础笔记(3)----函数

    前言引入函数前,所有的代码都写在main主函数中,代码过多,代码冗余,可读性差. 引入函数后,函数是实现某一特定功能的代码块.一个类中可以定义多个函数,每个函数和main主函数都是并列关系. 函数: ...

  4. php数组排序和查找的算法

    1.php算法 // 算法 // 1.冒泡排序 => 思路:​每次循环排列出一个最大的数 // echo '<pre>'; $arr = [ 1,43,54,62,21,66,32, ...

  5. 浅谈element-ui中的BEM范式实践

    日常的工作中,我们无时无刻不在和样式打交道.没有样式的页面就如同一部电影,被人随意地在不同地方做了截取. BEM规范应该是对于我们现在前端组件开发中我觉得是最合适的一套范式了.所以,我在自己的日常工作 ...

  6. 总结随笔(Beta)

    听说 -- beta冲刺总结 beta冲刺成员名单 姓名 学号 负责方向 个人主页 周龙荣 031402543 前端页面.跳转 http://www.cnblogs.com/ZHOULR/ 李家鹏 0 ...

  7. C语言第一次博客作业—输入输出

    一.PTA实验作业 题目1:7-3 温度转换 本题要求编写程序,计算华氏温度150°F对应的摄氏温度.计算公式:C=5×(F−32)/9,式中:C表示摄氏温度,F表示华氏温度,输出数据要求为整型. 1 ...

  8. verilog学习笔记(4)_有限状态机

    有限状态机: 有限状态机是由寄存器组和组合逻辑构成的硬件时序电路: - 其状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态: - 究竟转 ...

  9. Flask 扩展 HTTP认证

    Restful API不保存状态,无法依赖Cookie及Session来保存用户信息,自然也无法使用Flask-Login扩展来实现用户认证.所以这里,我们就要介绍另一个扩展,Flask-HTTPAu ...

  10. 总体来说,require_once 肯定要比 require 性能好

    首先,总体来说,require_once 肯定要比 require 性能好. 因为 require 某个文件等同于 "编译 + 执行" 这个文件:require_once 避免了对 ...