ASP.NET Web API是如何根据请求选择Action的?[上篇] 【转】
http://www.cnblogs.com/leo_wl/p/3316548.html
ASP.NET Web API是如何根据请求选择Action的?[上篇]
Web API的调用请求总是针对定义在某个HttpController中的某个Action方法,请求响应的内容来源于调用目标Action方法的执行结果。 当ASP.NET Web API为当前请求成功激活目标HttpController之后,后续的操作就是为请求在该HttpController中选择出对应的Action方 法。[本文已经同步到《How ASP.NET Web API Works?》]
HttpActionSelector
在对用于描述定义在HttpController中的Action方法的HttpActionDescriptor对象具有充分了解之后,我们开始 正式介绍真正用于选择目标Action方法的HttpActionSelector对象。ASP.NET Web API中的HttpActionSelector均实现了IHttpActionSelector接口。
1: public interface IHttpActionSelector
2: {
3: ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor);
4: HttpActionDescriptor SelectAction(HttpControllerContext controllerContext);
5: }
如上面的代码片断所示,IHttpActionSelector接口中定义了两个方法。GetActionMapping方法返回定义在指定 HttpController中所有Action与其名称的映射。该方法唯一的参数表示用于描述目标HttpController的 HttpControllerDescriptor对象,返回类型ILookup<string, HttpActionDescriptor>,其Key和Element分别表示Action的名称和用于描述Action方法的 HttpActionDescriptor对象。
由于同一个HttpController类型中可以定义多个同名的Action方法重载,我们也可以通过ActionNameAttribute特 性为多个Action方法指定相同的Action名称,所以多个Action方法可以共享相同的名称,所以GetActionMapping方法才会返回 一个ILookup<string, HttpActionDescriptor>对象。
针对请求对目标Action的选择实现在SelectAction方法中,作为该方法唯一参数的是表示当前HttpController上下文的 HttpControllerContext对象,我们可以从中获取表示当前请求的HttpRequestMessage对象和通过ASP.NET Web API路由系统生成的HttpRouteData。该方法返回的HttpActionDescriptor正是对最终用于处理当前请求的Action方法 的描述。
ApiControllerActionSelector
与我们在前面介绍的众多“标准化组件”一样,ASP.NET Web API默认用于选择目标Action的HttpActionSelector也是注册在当前的ServicesContainer中,我们可以直接通过 ServicesContainer具有如下定义的扩展方法GetActionSelector得到这个注册的HttpActionSelector。
1: public static class ServicesExtensions
2: {
3: //其他成员
4: public static IHttpActionSelector GetActionSelector(this ServicesContainer services);
5: }
通过分析如下所示的DefaultServices构造函数的定义我们知道默认使用的HttpActionSelector是一个类型为ApiControllerActionSelector的对象。
1: public class DefaultServices : ServicesContainer
2: {
3: // 其他成员
4: public DefaultServices(HttpConfiguration configuration)
5: {
6: //其他操作
7: this.SetSingle<IHttpActionSelector>(new ApiControllerActionSelector());
8: }
9: }
ApiControllerActionSelector定义在“System.Web.Http.Controllers”命名空间下,基本的成员定义如下所示。
1: public class ApiControllerActionSelector : IHttpActionSelector
2: {
3: public ApiControllerActionSelector();
4: public virtual ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor);
5: public virtual HttpActionDescriptor SelectAction(HttpControllerContext controllerContext);
6: }
有效的Action方法
现在我们来着重讨论ApiControllerActionSelector的GetActionMapping方法的实现。实现逻辑其实很简单:它 通过作为参数的HttpControllerDescriptor得到HttpController的真实类型,并调用GetMethods方法获得描述 所有方法成员MethodInfo列表,然后从中筛选出所有“有效”的Action方法并以此创建 ReflectedHttpActionDescriptor对象。那么一个有效的Action方法具有怎样的“资质”呢?
对于一个实现了IHttpController接口的HttpController类型来说,其拥有的所有MethodInfo必须同时满足如下的条件才会被视为有效的Action方法并被用于创建对应的HttpActionDescriptor对象:
- 必须是公有的实例方法。
- MethodInfo的IsSpecialName属性值为False(表示属性成员Getter和Setter的MethodInfo不会被用于创建HttpActionDescriptor)。
- 从ApiController类型中继承的方法不是有效的Action方法
所有有效的MethodInfo被选择出来并连同指定的HttpControllerDescriptor一起生成一组 ReflectedHttpActionDescriptor对象集合,它被转换成一个ILookup<string, HttpActionDescriptor>对象后直接作为GetActionMapping方法的返回值。如下的代码片断基本反映了 GetActionMapping方法中最初生成HttpActionDescriptor与其Action名称映射的逻辑。
1: public class ApiControllerActionSelector : IHttpActionSelector
2: {
3: //其他成员
4: public ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor)
5: {
6: IEnumerable<ReflectedHttpActionDescriptor> actionDescriptor =
7: from method in controllerDescriptor.ControllerType.GetMethods()
8: where method.IsPublic && !method.IsStatic && !method.IsSpecialName&& !method.DeclaringType.IsAssignableFrom(typeof(ApiController))
9: select new ReflectedHttpActionDescriptor(controllerDescriptor,method);
10: return actionDescriptor.ToLookup(action => action.ActionName, action => (HttpActionDescriptor)action);
11: }
12: }
为了避免频繁、重复地对类型的方法成员进行反射而影响性能,定义在上面代码片断的操作仅仅会在第一次调用GetActionMapping方法时被执行。生成的ReflectedHttpActionDescriptor会被缓存起来以服务于后续调用。
ActionMethodSelector
HttpActionSelector的终极目标是根据当前请求从目标HttpController中选择出正确的Action方法,这个目标实现 在它的SelectAction方法中。在系统介绍实现在ApiControllerActionSelector的SelectAction方法中的 Action选择机制之前,我们还需要了解另一个与之相关的对象:ActionMethodSelector。
ActionMethodSelector的目的在于判断某个Action方法是否与当前请求相匹配,它们均实现了具有 如下定义的IActionMethodSelector接口。IActionMethodSelector仅仅是定义在程序集 System.Web.Http.dll中的一个内部接口而已,它定义了一个唯一的方法IsValidForRequest,方法的两个参数分别是表示当 前 HttpController上下文的HttpControllerContext对象和代码目标Action方法的MethodInfo。执行该方法得 到的布尔值表明目标Action方法是否能够用于处理当前请求。
1: internal interface IActionMethodSelector
2: {
3: bool IsValidForRequest(HttpControllerContext controllerContext, MethodInfo methodInfo);
4: }
ASP.NET Web API仅仅定义了唯一一个实现了这个IActionMethodSelector接口的类型,它就是具有如下定义的NonActionAttribute。顾名思义,如果在某个方法上应用了这个特性,意味着目标方法不是一个合法的Action方法。从给出的代码片断可以看出NonActionAttribute直接在实现的IsValidForRequest方法中返回False。
1: [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)]
2: public sealed class NonActionAttribute : Attribute, IActionMethodSelector
3: {
4: bool IActionMethodSelector.IsValidForRequest(HttpControllerContext controllerContext, MethodInfo methodInfo)
5: {
6: return false;
7: }
8: }
对于NonActionAttribute特性来说,有一点值得强调:虽然应用了该特性的方法被认为不再是一个合法的Action方法,但是ApiControllerActionSelector的GetActionMapping方法并不会使用它来判断Action方法的有效性。
在《下篇》中我们将以实例的形式讨论该主题最为核心的内容:ASP.NET Web API如何利用HttpActionSelector在目标HttpController成功激活之后如何从中选择出匹配的Action方法来处理当前的请求的。
ASP.NET Web API是如何根据请求选择Action的?[上篇] 【转】的更多相关文章
- ASP.NET Web API是如何根据请求选择Action的?[下篇]
ASP.NET Web API是如何根据请求选择Action的?[下篇] 再<上篇>中我们简单介绍了用于实现Action选择机制的HttpActionSelector,接下来我们来讨论本章 ...
- ASP.NET Web API是如何根据请求选择Action的?[上篇]
ASP.NET Web API是如何根据请求选择Action的?[上篇] Web API的调用请求总是针对定义在某个HttpController中的某个Action方法,请求响应的内容来源于调用目标A ...
- ASP.NET Web API是如何根据请求选择Action的?[下篇] 【转】
再<上篇>中我们简单介绍了用于实现Action选择机制的HttpActionSelector,接下来我们来讨论本章最为核心的内 容:ASP.NET Web API如何利用HttpActio ...
- Self Host模式下的ASP. NET Web API是如何进行请求的监听与处理的?
构成ASP.NET Web API核心框架的消息处理管道既不关心请求消息来源于何处,也不需要考虑响应消息归于何方.当我们采用Web Host模式将一个ASP.NET应用作为目标Web API的宿主时, ...
- 【转】WCF和ASP.NET Web API在应用上的选择
文章出处:http://www.cnblogs.com/shanyou/archive/2012/09/26/2704814.html 在最近发布的Visual Studio 2012及.NET 4. ...
- WCF和ASP.NET Web API在应用上的选择
小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/shareto ...
- [转载]WCF和ASP.NET Web API在应用上的选择
http://www.cnblogs.com/shanyou/archive/2012/09/26/2704814.html http://msdn.microsoft.com/en-us/libra ...
- WCF和ASP.NET Web API在应用上的选择(转)
出处:http://www.cnblogs.com/shanyou/archive/2012/09/26/2704814.html 在最近发布的Visual Studio 2012及.NET 4.5中 ...
- ASP.NET Web API 2.0新特性:Attribute Routing1
ASP.NET Web API 2.0新特性:Attribute Routing[上篇] 对于一个针对ASP.NET Web API的调用请求来说,请求的URL和对应的HTTP方法的组合最终决定了目标 ...
随机推荐
- Python+Selenium练习篇之5-利用partial link text定位元素
本文介绍如何通过partial link text来定位页面元素.看到这个,有点和前一篇文字link text有点类似.字面意思,确实和link text相类似,partial link text就是 ...
- day05_07 标志位讲解
continue: 需求:大于5才打印 for i in range(10): if i<6 : continue print(i) continue作用:结束本次循环,继续下次循环 break ...
- Leetcode 617.合并二叉树
合并二叉树 给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠. 你需要将他们合并为一个新的二叉树.合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新 ...
- 频繁模式挖掘中Apriori、FP-Growth和Eclat算法的实现和对比(Python实现)
最近上数据挖掘的课程,其中学习到了频繁模式挖掘这一章,这章介绍了三种算法,Apriori.FP-Growth和Eclat算法:由于对于不同的数据来说,这三种算法的表现不同,所以我们本次就对这三种算法在 ...
- C#控制台程序读取项目中文件路径
//使用appdomain获取当前应用程序集的执行目录 string dir = AppDomain.CurrentDomain.BaseDirectory; //使用path获取当前应用程序集的执行 ...
- chrome+postman测试rest请求
1.在chrome安装postman 2.在chrome打开postman 浏览器输入:chrome://apps/ 选择你的postman 3.在你看到的postman中 normal中可以看到参数 ...
- Groovy安装
进入Groovy的官网下载安装SDKMAN() 以下是官网的下载方法(http://www.groovy-lang.org/download.html) This tool makes install ...
- Ansible实战之Nginx高可用代理LNMP-wordpress
author:JevonWei 版权声明:原创作品 blog:http://119.23.52.191/ --- 实验环境:前端使用Nginx做代理服务器,静态资源经由缓存服务器,连接后端web集群, ...
- "二进制" 转化为 "十六进制
//"二进制" 转化为 "十六进制" void To_string(uint8 *dest,char * src,uint8 length) { uint8 * ...
- Redis主从复制简单介绍
由于本地环境的使用,所以搭建一个本地的Redis集群,本篇讲解Redis主从复制集群的搭建,使用的平台是Windows,搭建的思路和Linux上基本一致! (精读阅读本篇可能花费您15分钟,略读需5分 ...