WebApi-路由机制
一、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方法中通过如下方式获得:
1 IHttpRouteData routeData = Request.GetRouteData(); 2 IDictionary<string, object> routeDataValues = routeData.Values;
这里需要澄清的几点的是:
1、URL未匹配上任何路由 和 匹配上了路由但是未找到相应的Controller和Action 是两个不同的概念,IIS对这两种情况的响应是不一样的。
URL未匹配上路由:
如果用户请求的接口的地址不能和路由表中的所有路由相匹配,IIS将直接报告404错误。
匹配上了路由但未找到相应Controller或Action:
如果匹配上了路由但是未找到响应的Controller或Action,那么将报类似如下错误:
MessageDetail节点详细描述了是 Controller未找到还是 Action未找到。
2、由于路由表中可以配置一条或者多条路由,并且WebApi框架在匹配成功一条路由后将不再继续往下匹配,也就是说即使此时后面还有路由可以
和当前请求匹配也不会被匹配到,所以请务必注意每条路由的配置顺序,否则可能造成意想不到的结果。
如:
1 public static void Register(HttpConfiguration config) 2 { 3 config.Routes.MapHttpRoute( 4 name: "TestRoute", 5 routeTemplate: "{controller}/{action}", 6 defaults: new { action = "Index" } 7 ); 8 config.Routes.MapHttpRoute( 9 name: "DefaultApi", 10 routeTemplate: "api/{controller}/{id}", 11 defaults: new { id = RouteParameter.Optional } 12 ); 13 14 }
假设我们此时代码中包含如下控制器和Action:
1 public class ValuesController : ApiController 2 { 3 public string Get() 4 { 5 return "value"; 6 } 7 [HttpGet] 8 public object QueryValues(int index) 9 { 10 string[] strs = new string[] { "张三", "李四" }; 11 if (index < 0 || index >= strs.Length) 12 { 13 return JsonConvert.SerializeObject(strs); 14 } 15 return strs[index]; 16 } 17 }
我们在浏览器中输入: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框架定义的接口,定义如下:
1 public interface IHttpControllerSelector 2 { 3 // Methods 4 IDictionary<string, HttpControllerDescriptor> GetControllerMapping(); 5 HttpControllerDescriptor SelectController(HttpRequestMessage request); 6 }
WebApi框架对控制器的匹配进行了默认的实现,类名叫做:DefaultHttpControllerSelector,这个类默认实现了查找Controller的过程,在DefaultHttpControllerSelector内部通过
IHttpControllerTypeResolver接口加载出所有的满足条件的控制器类型,能被加载并查找的控制器类型必须满足以下条件:
1、类必须是实现了IHttpController接口
2、必须是public
3、不能是abstract类
4、类名必须以Controller结尾
最终,从这些列表中找出名称和路由数据中的Controller名同名的Controller类,并创建该类的实例对象。
当然如果我们需要有自己的控制器匹配的逻辑,我们也可以对其进行配置,通过在:/App_Start/WebApiConfig.cs类中进行配置,配置方式如下所示:
1 public static class WebApiConfig 2 { 3 public static void Register(HttpConfiguration config) 4 { 5 // 这里我们配置成使用自己写的匹配控制器的逻辑 6 GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new MyHttpControllerSelectory(GlobalConfiguration.Configuration)); 7 } 8 }
虽然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接口定义如下:
1 public interface IHttpActionSelector 2 { 3 // Methods 4 ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor); 5 HttpActionDescriptor SelectAction(HttpControllerContext controllerContext); 6 }
需要说明的是:能作为Action被执行的方法必须满足以下几点:
1、必须是public修饰的方法
2、未被[NonAction]特性修饰的方法
3、不是从ApiController类中继承过来的方法
4、控制器的构造函数,等等也不会被匹配。
Action的匹配我们也可以实现自定义匹配规则,和上面提到的自定义Controller匹配规则的配置方式类似,如下:
1 public static void Register(HttpConfiguration config) 2 { 3 GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionSelector), new MyApiControllerActionSelector()); 4 5 }
本文主要讲述了WebApi框架如何将来自用户的接口调用请求映射到具体的Controller和Action,并对其进行执行的过程,最容易让人困惑的部分或许还是Action的选择部分,
后续我们将继续讨论关于Action选择部分的具体细节以及参数绑定过程。
Visual Studio 2015中的常用调试技巧分享
.NET 技术交流群:337901356 欢迎您的加入!
为什么要学习调试?
调试(Debug)是作为一个程序员必须要学会的东西,学会调试可以极大的提高开发效率,排错时间,很多人不喜欢调试,但我认为这是一个很不可取的选择,调试的时候能让我们看到程序的执行顺序、步骤以及过程等,调试的时候可以让我们监视代码中各个变量的情况,调试让我们可以让我们快速的找出错误的根源。可见调试是至关重要的。
要学习好怎么调试,那么必须去了解VS 这个IDE中的各种调试技巧,下面我就讲讲我所经常在调试程序中所用到的技巧。
调试技巧介绍
1、监视窗口(Ctrl+D,Ctrl+W 快捷键开启)
我们在调试程序的过程中,可以通过此窗口动态查看各个变量的值,以及各个函数的调用的返回结果。
在监视窗口中,我们还可以手动更改某个变量的值,这个有时候很有用,特别是有时候程序执行到指定语句的时候,发现某个值是错误的,但是我们又想用一个正确值测试代码时,
此时可以通过监视窗口直接更改变量的值,而不需要重新启动调试。
快速监视:选中某个变量后者表达式,然后通过按下快捷键Ctrl+D,Ctrl+Q 开启。
备注:只能在调试情况下才能开启此窗口。
2、调用堆栈(Ctrl+D,Ctrl+C)
通过该窗口,我们可以看到函数的一级一级的调用过程,我们就可以知道,该方法是来自于上面的哪一个步骤发起的调用。、
可以通过点击调试->窗口->调用堆栈 来打开调用堆栈窗口。
如下图:
备注:只能在调试情况下在可以开启此窗口。
3、拖动调试光标的技巧。
Visual Studio 在调试的情况下可以拖动左侧的黄色箭头进行上下拖动,那么这个有什么作用呢,有时候我们可能想实用F11跟到某个方法里面进行调用过程的查看,结果一个不小心发现手误按下了F10,此时代码执行到了方法调用的下一句,那么我们此时就可以点击左侧的黄色箭头,并按住鼠标左键,往上一拖,这个时候,就又可以执行刚才的方法调用的那句代码了,如果往下拖,那么可以跳过一些语句代码的执行。
4、编辑并继续
通过启用编辑并继续,可以在调试代码的过程中直接更改部分代码,然后立刻执行最新的代码,而不需要重新启动调试程序。
但是这种方式在WEB应用程序中有个不好的地方就是,设置了启动编辑并继续之后,如果此时结束调试,那么网站或WEB应用程序将自动从IISExpress中退出,也就是此时再刷新网页,将会显示无法连接到网站,如果要在继续浏览其他页面,那么此时就要重新启动网站了。
不过,在Visual Studio 2015中,默认就是打开了编辑并继续功能,并且已经把编辑并继续的复选框给去掉了。
5、设置断点(F9 快捷键开启)
断点的好处在于,如果方法或者程序中包含了大量的代码,那么我们就可以设置到一个我们想让程序停下来的地方,通过F5可以快速的执行到下一个断点处。
当我们启动调试后,如果程序中有大量的断点,而我们只是想调试某一部分代码,那么或许有些人会一个一个断点去取消或者禁用,感觉够累,
其实是可以通过 点击 调试->禁用所有断点 或者调试->删除所有断点,如果你决定不需重新设置那些断点了,那么可以删除所有断点,否则建议先禁用所有断点,然后在你需要启用断点调试的地方再把那些断点启用。
有一个比较特殊的断点设置就是:条件断点
条件断点就是可以在设置一个表达式,只有表达式的值为true或者更改的时候,语句才会被命中。
看个例子。
6、F5按键的使用
Visual Studio 中,F5可以用来启动调试、也可以快速的将程序执行从一个断点执行到下一个断点处,往往有些新手会一句一句的执行进行调试,如果程序代码没几句还好,如果程序代码量多,或者碰到一个大循环的化,那要手按到何时才能执行到指定的想调试的代码处呢。
7、F10 逐过程
F10表示逐过程执行代码,什么是逐过程执行呢,通俗点说就是当执行到方法的语句时,调试不会进入到方法内部,而是一步将方法执行完毕。
8、F11 逐语句
F11是逐语句执行代码,那么如果碰到调用方法的语句时,那么通过F11可以进入到方法内部的执行过程。
9、切换完成模式
有时候你是不是发现手动打了一部分英文之后,那个智能提示框总是不能自动选中我们想要选中的,而是变成下面那样:
、
那么,你可以输入快捷键:Ctrl+Alt+空格键来切换到到选中模式。
总的来说主要的调试技巧就是这些,这里讲解的都是日常开发调试中个比较常用的,希望给新手们有所帮助。