接着上文Asp.net web Api源码分析-Filter 我们提到filter的获取和调用,后面通过HttpActionBinding actionBinding = actionDescriptor.ActionBinding;来获取HttpActionBinding实例,然后调用 HttpActionBinding的ExecuteBindingAsync方法来绑定Action参数。HttpActionDescriptor中 定义了ActionBinding属性,默认的实现代码:

ServicesContainer controllerServices = _controllerDescriptor.Configuration.Services;
 IActionValueBinder actionValueBinder = controllerServices.GetActionValueBinder();
 HttpActionBinding actionBinding = actionValueBinder.GetBinding(this);

这里的actionValueBinder默认就是一个DefaultActionValueBinder实例,然后调用它的GetBinding方法。然我们看看DefaultActionValueBinder的GetBinding方法:

public virtual HttpActionBinding GetBinding(HttpActionDescriptor actionDescriptor)
        {
            if (actionDescriptor == null)
            {
                throw Error.ArgumentNull("actionDescriptor");
            }

HttpParameterDescriptor[] parameters = actionDescriptor.GetParameters().ToArray();
            HttpParameterBinding[] binders = Array.ConvertAll(parameters, GetParameterBinding);

HttpActionBinding actionBinding = new HttpActionBinding(actionDescriptor, binders);

EnsureOneBodyParameter(actionBinding);

return actionBinding;
        }

这里首先获取当前HttpActionDescriptor的参数集合ReflectedHttpParameterDescriptor[],然后依次调用GetParameterBinding方法把当前HttpActionDescriptor转化为HttpParameterBinding,GetParameterBinding方法如下:

  protected virtual HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter){// Attribute has the highest precedence// Presence of a model binder attribute overrides.ParameterBindingAttribute attr = parameter.ParameterBinderAttribute;if (attr != null){return attr.GetBinding(parameter);}// No attribute, so lookup in global map.ParameterBindingRulesCollection pb = parameter.Configuration.ParameterBindingRules;if (pb != null){HttpParameterBinding binding = pb.LookupBinding(parameter);if (binding != null){return binding;}}// Not explicitly specified in global map or attribute.// Use a default policy to determine it. These are catch-all policies. Type type = parameter.ParameterType;if (TypeHelper.IsSimpleUnderlyingType(type) || TypeHelper.HasStringConverter(type)){// For simple types, the default is to look in URI. Exactly as if the parameter had a [FromUri] attribute.return parameter.BindWithAttribute(new FromUriAttribute());}// Fallback. Must be a complex type. Default is to look in body. Exactly as if this type had a [FromBody] attribute.attr = new FromBodyAttribute();return attr.GetBinding(parameter);}

这里我们首先调用 ParameterBindingAttribute attr = parameter.ParameterBinderAttribute;来获取ParameterBindingAttribute实例,然后调用它的 GetBinding方法来获取HttpParameterBinding,我们还是来看看ParameterBinderAttribute是如何定义 了吧:

在HttpParameterDescriptor中的ParameterBinderAttribute属性定义如下:

public virtual ParameterBindingAttribute ParameterBinderAttribute
        {
            get
            {
                if (_parameterBindingAttribute == null)
                {
                    if (!_searchedModelBinderAttribute)
                    {
                        _searchedModelBinderAttribute = true;
                        _parameterBindingAttribute = FindParameterBindingAttribute();
                    }
                }

return _parameterBindingAttribute;
            }

set { _parameterBindingAttribute = value; }
        }

FindParameterBindingAttribute其实就是查找参数或则参数类型的ParameterBindingAttribute特性,如果这里取到的ParameterBindingAttribute属性多余一个则最后要抛出异常,具体这里就不说了。

回到DefaultActionValueBinder中GetParameterBinding方法,找不到 ParameterBindingAttribute对象,我们就 parameter.Configuration.ParameterBindingRules来获取 ParameterBindingRulesCollection实例,其中 ParameterBindingRules=DefaultActionValueBinder.GetDefaultParameterBinders(), 其中GetDefaultParameterBinders方法实现如下:

internal static ParameterBindingRulesCollection GetDefaultParameterBinders()
        {
            ParameterBindingRulesCollection pb = new ParameterBindingRulesCollection();

pb.Add(typeof(CancellationToken), parameter => new CancellationTokenParameterBinding(parameter));
            pb.Add(typeof(HttpRequestMessage), parameter => new HttpRequestParameterBinding(parameter));

// Warning binder for HttpContent.
            pb.Add(parameter => typeof(HttpContent).IsAssignableFrom(parameter.ParameterType) ?
                                    parameter.BindAsError(Error.Format(SRResources.ParameterBindingIllegalType, parameter.ParameterType.Name, parameter.ParameterName))
                                    : null);

return pb;
        }

这里的ParameterBindingRulesCollection实例有3个成员,然后调用 ParameterBindingRulesCollection的LookupBinding方法来获取HttpParameterBinding实 例,其中LookupBinding方法如下:

public class ParameterBindingRulesCollection : Collection<Func<HttpParameterDescriptor, HttpParameterBinding>>
{
     private static Func<HttpParameterDescriptor, HttpParameterBinding> TypeCheck(Type type, Func<HttpParameterDescriptor, HttpParameterBinding> func)
    {
        return (param => (param.ParameterType == type) ? func(param) : null);
    }
    public void Add(Type typeMatch, Func<HttpParameterDescriptor, HttpParameterBinding> funcInner)
    {
        Add(TypeCheck(typeMatch, funcInner));
    }
    public HttpParameterBinding LookupBinding(HttpParameterDescriptor parameter)
    {
        foreach (Func<HttpParameterDescriptor, HttpParameterBinding> func in this)
        {
            HttpParameterBinding binding = func(parameter);
            if (binding != null)
            {
                 return binding;
            }
        }
        return null;
    }
}

所以这里默认的ParameterBindingRulesCollection3个成员是不会返回HttpParameterBinding实例。

如果参数类型是一个简单类型,并且该类型可以转化为string类型,然后调用  return parameter.BindWithAttribute(new FromUriAttribute());返回HttpParameterBinding,BindWithAttribute方法其实就是调用ParameterBindingAttribute的GetBinding方法,这里默认FromUriAttribute的GetBinding方法,这里FromUriAttribute的继承数如下:FromUriAttribute-》ModelBinderAttribute-》ParameterBindingAttribute。这里的

如果绑定的参数数据类型比较特殊,那么这里我们就调用FromBodyAttribute的GetBinding方法来获取HttpParameterBinding实例,这里的FromBodyAttribute继承树如下:

FromBodyAttribute-》ParameterBindingAttribute

在这里我们总结一下这里找HttpParameterBinding的顺序,(1)parameter.ParameterBinderAttribute实际就是找参数或参数类型的ParameterBindingAttribute属性,(2)

parameter.Configuration.ParameterBindingRules 从全局的ParameterBindingRules中找HttpParameterBinding,(3)如果参数类型是一个简单类型且可以转化为 string那么我们调用parameter.BindWithAttribute(new FromUriAttribute()),(4)最后我们调用FromBodyAttribute的GetBinding方法来获取 HttpParameterBinding实例。

现在我们回到DefaultActionValueBinder的GetBinding方法中来,现在我们已经获取到HttpParameterBinding集合,接下里创建一个HttpActionBinding实例,最后调用EnsureOneBodyParameter来检查HttpActionBinding的ParameterBindings集合是否有2个都需要读取form表单,如果是则抛出异常。到这里HttpActionDescriptor的ActionBinding的创建也就很清楚了。

回到ApiController的ExecuteAsync方法中来,这里继续调用HttpActionBinding的ExecuteBindingAsync方法,这里的ExecuteBindingAsync方法实现如下:

public virtual Task ExecuteBindingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            if (_parameterBindings.Length == 0)
            {
                return TaskHelpers.Completed();
            }

// First, make sure the actionBinding is valid before trying to execute it. This keeps us in a known state in case of errors.
            foreach (HttpParameterBinding parameterBinder in ParameterBindings)
            {
                if (!parameterBinder.IsValid)
                {
                    // Throwing an exception because the webService developer's action signature is bad.
                    // This exception will be caught and converted into a 500 by the dispatcher
                    return TaskHelpers.FromError(new InvalidOperationException(parameterBinder.ErrorMessage));
                }
            }

if (_metadataProvider == null)
            {
                HttpConfiguration config = actionContext.ControllerContext.Configuration;
                _metadataProvider = config.Services.GetModelMetadataProvider();
            }

// Execute all the binders.
            IEnumerable<Task> tasks = from parameterBinder in ParameterBindings select parameterBinder.ExecuteBindingAsync(_metadataProvider, actionContext, cancellationToken);
            return TaskHelpers.Iterate(tasks, cancellationToken, disposeEnumerator: false);
        }

这个方法逻辑很简单,如果ParameterBindings没有成员则直接返回,如果有则需要依次验证他们的IsValid,然后再依次调用他们的ExecuteBindingAsync方法,ExecuteBindingAsync方法的具体执行我们这里就不多说了。这里我们看看metadataProvider 是个什么东东吧,     SetSingle<ModelMetadataProvider>(new DataAnnotationsModelMetadataProvider());这里我们就知道metadataProvider 其实是一个DataAnnotationsModelMetadataProvider实例,其构造函数也没什么特别的。这里返回的Task的具体实现我就不多说了,里面用到了一个TaskCompletionSource类,具体的使用我这里一而不说了。

Asp.net web Api源码分析-HttpParameterBinding相关推荐

  1. 【es】es API源码分析

    1.概述 转载:[6]elasticsearch源码深入分析--API源码分析 2.RestController的继承关系 从Node实例化的过程中,我们知道ActionModule是Node提供Re ...

  2. Android 系统(78)---《android framework常用api源码分析》之 app应用安装流程

    <android framework常用api源码分析>之 app应用安装流程 <android framework常用api源码分析>android生态在中国已经发展非常庞大 ...

  3. Linux项目实战C++轻量级Web服务器源码分析TinyWebServer

    目录 文章简介 一. 先跑起来项目 二.再看项目核心 三.逐个击破!立下flag 文章简介 TinyWebServer是Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的 ...

  4. MapGuide源码分析----MapGuide Web扩展源码分析

    本节中,我们将通过介绍如何完成枚举资源功能来介绍MapGuide Web扩展的部分源代码. 在浏览器端的地址栏输入类似如下字符串,就会发送一个枚举资源的HTTP请求. http://hostname/ ...

  5. ASP.NET WebForm / MVC 源码分析

    WebForm:https://www.cnblogs.com/Dr-Hao/p/5315448.html MVC:http://www.cnblogs.com/DrHao/p/5315556.htm ...

  6. 【ES源码分析】强制合并分段(_forcemerge API)源码分析

    _forcemerge API 源码分析 文章目录 _forcemerge API 源码分析 合并方式 只合并删除文档 没有限制最大segment数的合并 限制了最大segment数的合并 合并策略 ...

  7. 【转】ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  8. JDK源码分析 FutureTask源码分析

    文章目录 前言 一.Callable接口 二.Future接口 三.FutureTask源码分析 3.1 Future继承结构图 3.2 参数介绍 3.3 构造函数 3.4. FutureTask的A ...

  9. java 源代码 分析_Java Collections 源码分析

    Java Collections API源码分析 侯捷老师剖析了不少Framework,如MFC,STL等.侯老师有句名言: 源码面前,了无秘密 这句话还在知乎引起广泛讨论. 我对教授程序设计的一点想 ...

最新文章

  1. docker上传自己的镜像
  2. 微软职位内部推荐-SDEII for Windows Phone Apps
  3. shuffleNetv2 测试
  4. eval?python顺序列表模拟栈实现计算器
  5. 依赖注入Bean属性——手动装配Bean
  6. linux 安装qt 4.6软件,QT学习之一:Linux下安装QT之版本qt-4.6.3
  7. php array第一张图片_PHP array_udiff() 函数
  8. button 隐藏属性_PyQt5实现仿QQ贴边隐藏功能!有点意思
  9. callablestatement存储过程
  10. 软考网络管理员学习笔记6之第六章互联网技术
  11. 3_数据分析—数据清洗及特征处理
  12. Timemator for Mac(自动化计时管理软件)
  13. ECMAScript 基础--原始值和引用值
  14. 【GCC】gcc编译器的使用
  15. Oracle 12c RAC 安装文档
  16. webstorm 一次Git使用很卡的处理记录
  17. P6225 [eJOI2019] 异或橙子
  18. Qt 3D Overview
  19. 关于Windows聚焦一直保持一个图不变(搬运后加了图,留着以后用)
  20. 微信小程序,不可不知的一二三四

热门文章

  1. androidstudio 日历视图怎么显示农历_中秋国庆旅游攻略怎么做?用这个便签软件很简单...
  2. Vivado工程文件分类
  3. C++ Priemer目录索引
  4. 信号 09 | SIGCLD语义
  5. 网易严选Java开发三面面经:java读文件内容
  6. 现在做Android开发有前途吗?附面试题答案
  7. python接口自动化(四)--接口测试工具介绍(详解)
  8. 51nod1270(dp)
  9. 第 39 章 ThinkPHP--CURD 操作
  10. Android API中被忽略的几个函数接口