紧接着上篇asp.net mvc源码分析-Action篇 Filter 中提到了  IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);首先这个方法的目的很明白获取当前Action参数名称和值得一个字典。

protected virtual IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
            Dictionary<string, object> parametersDict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
            ParameterDescriptor[] parameterDescriptors = actionDescriptor.GetParameters();

foreach (ParameterDescriptor parameterDescriptor in parameterDescriptors) {
                parametersDict[parameterDescriptor.ParameterName] = GetParameterValue(controllerContext, parameterDescriptor);
            }
            return parametersDict;
        }

这个代码逻辑很简单吧,有前面的文章我们知道这里的actionDescriptor 是一个ReflectedActionDescriptor实例,我们猜测ParameterDescriptor是Paramete的一个包装类,具体返回应该是它的子类。 的GetParameters方法如下

public override ParameterDescriptor[] GetParameters() {
            ParameterDescriptor[] parameters = LazilyFetchParametersCollection();

// need to clone array so that user modifications aren't accidentally stored
            return (ParameterDescriptor[])parameters.Clone();
        }

private ParameterDescriptor[] LazilyFetchParametersCollection() {
            return DescriptorUtil.LazilyFetchOrCreateDescriptors<ParameterInfo, ParameterDescriptor>(
                ref _parametersCache /* cacheLocation */,
                MethodInfo.GetParameters /* initializer */,
                parameterInfo => new ReflectedParameterDescriptor(parameterInfo, this) /* converter */);
        }

一看到LazilyFetchOrCreateDescriptors这个名称我们就知道 如果有就直接获取,没有就创建。

public static TDescriptor[] LazilyFetchOrCreateDescriptors<TReflection, TDescriptor>(ref TDescriptor[] cacheLocation, Func<TReflection[]> initializer, Func<TReflection, TDescriptor> converter) {
            // did we already calculate this once?
            TDescriptor[] existingCache = Interlocked.CompareExchange(ref cacheLocation, null, null);
            if (existingCache != null) {
                return existingCache;
            }

TReflection[] memberInfos = initializer();
            TDescriptor[] descriptors = memberInfos.Select(converter).Where(descriptor => descriptor != null).ToArray();
            TDescriptor[] updatedCache = Interlocked.CompareExchange(ref cacheLocation, descriptors, null);
            return updatedCache ?? descriptors;
        }

这里的memberInfos=MethodInfo.GetParameters()获取Actin的所有参数。而converter=new ReflectedParameterDescriptor(parameterInfo, this),ReflectedParameterDescriptor构造函数如下:

public ReflectedParameterDescriptor(ParameterInfo parameterInfo, ActionDescriptor actionDescriptor) {
            ParameterInfo = parameterInfo;
            _actionDescriptor = actionDescriptor;
            _bindingInfo = new ReflectedParameterBindingInfo(parameterInfo);
        }

在这个ReflectedParameterDescriptor有个属性需要我们注意一下,那就是DefaultValue

public override object DefaultValue {
            get {
                object value;
                if (ParameterInfoUtil.TryGetDefaultValue(ParameterInfo, out value)) {
                    return value;
                }
                else {
                    return base.DefaultValue;
                }
            }
        }

 internal static class ParameterInfoUtil {public static bool TryGetDefaultValue(ParameterInfo parameterInfo, out object value) {// this will get the default value as seen by the VB / C# compilers// if no value was baked in, RawDefaultValue returns DBNull.Valueobject defaultValue = parameterInfo.DefaultValue;if (defaultValue != DBNull.Value) {value = defaultValue;return true;}// if the compiler did not bake in a default value, check the [DefaultValue] attributeDefaultValueAttribute[] attrs = (DefaultValueAttribute[])parameterInfo.GetCustomAttributes(typeof(DefaultValueAttribute), false);if (attrs == null || attrs.Length == 0) {value = default(object);return false;}else {value = attrs[0].Value;return true;}}}

  这段代码主要意思是先找到对象的parameterInfo.DefaultValue值,如果不是null这设置value=parameterInfo.DefaultValue并返回true,如果没有找到我们就找参数是否有DefaultValueAttribute特性,如果有就返回设置value=attrs[0].Value并返回true,否则value=default(object) 并返回false。一旦返回false,ReflectedParameterDescriptor的DefaultValue就会返回null。从这段带代码我们需要注意在申明默认参数尽量写成 public ActionResult Index(string name="majiang") 而不是 public ActionResult Index([DefaultValue("majiang")]string name)
现在我们再来看看构造函数中的那个ReflectedParameterBindingInfo,在参数绑定过程中并不是所有的参数都需要绑定数据的,有写参数是不需要绑定数据。

ReflectedParameterBindingInfo的主要代码如下:

public ReflectedParameterBindingInfo(ParameterInfo parameterInfo) {
            _parameterInfo = parameterInfo;
            ReadSettingsFromBindAttribute();
        }
  private void ReadSettingsFromBindAttribute() {
            BindAttribute attr = (BindAttribute)Attribute.GetCustomAttribute(_parameterInfo, typeof(BindAttribute));
            if (attr == null) {
                return;
            }

_exclude = new ReadOnlyCollection<string>(AuthorizeAttribute.SplitString(attr.Exclude));
            _include = new ReadOnlyCollection<string>(AuthorizeAttribute.SplitString(attr.Include));
            _prefix = attr.Prefix;
        }

ReadSettingsFromBindAttribute方法主要是获取参数的BindAttribute来初始化exclude排除参数,include包含参数。这个类还有一个比较特殊的属性
        public override IModelBinder Binder  这个将放到后面来说说。
         默认或则一般情况(简单类型)下我们不考虑什么排除参数的情况 获取到的BindAttribute为null。

现在我们已经得到Action的Parameters的一个包装对象集合ParameterDescriptor[]。同一个Action看你多次调用为了彼此不影响所以这里需要把这个ParameterDescriptor[]集合给克隆一份。 (ParameterDescriptor[])parameters.Clone();

紧接下来就是根据parameterDescriptor来获取真正值了,调用GetParameterValue方法。

 protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) {// collect all of the necessary binding propertiesType parameterType = parameterDescriptor.ParameterType;IModelBinder binder = GetModelBinder(parameterDescriptor);IValueProvider valueProvider = controllerContext.Controller.ValueProvider;string parameterName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;Predicate<string> propertyFilter = GetPropertyFilter(parameterDescriptor);// finally, call into the binderModelBindingContext bindingContext = new ModelBindingContext() {FallbackToEmptyPrefix = (parameterDescriptor.BindingInfo.Prefix == null), // only fall back if prefix not specifiedModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),ModelName = parameterName,ModelState = controllerContext.Controller.ViewData.ModelState,PropertyFilter = propertyFilter,ValueProvider = valueProvider};object result = binder.BindModel(controllerContext, bindingContext);return result ?? parameterDescriptor.DefaultValue;}

  这段代码说白了就是通过 binder.BindModel方法来获取值,如果没有找到就返回parameterDescriptor.DefaultValue。有关binder.BindModel这个方法很是复杂,需要IModelBinder、IValueProvider、ModelMetadataProvider这几个东西,所以我们将放到后面来统一讲解。

转载于:https://www.cnblogs.com/majiang/archive/2012/11/09/2763422.html

asp.net mvc源码分析-Action篇 ParameterDescriptor相关推荐

  1. asp.net mvc源码分析-Action篇 Action的执行

    接着上篇 asp.net mvc源码分析-Action篇 DefaultModelBinder 我们已经获取的了Action的参数,有前面的内容我们知道Action的调用时在ControllerAct ...

  2. asp.net mvc源码分析-Action篇 DefaultModelBinder

    接着上篇 asp.net mvc源码分析-Controller篇 ValueProvider 现在我们来看看ModelBindingContext这个对象. ModelBindingContext b ...

  3. asp.net mvc源码分析-Controllerl篇 ControllerDescriptor

    在上篇asp.net mvc源码分析-Controllerl篇 TempData数据存储 我们讲到了ActionInvoker.InvokeAction(ControllerContext, acti ...

  4. asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证

    asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证 原文:asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型 ...

  5. MVC源码分析 - Action查找和过滤器的执行时机

    接着上一篇, 在创建好Controller之后, 有一个 this.ExecuteCore()方法, 这部分是执行的. 那么里面具体做了些什么呢? //ControllerBaseprotected ...

  6. ASP.NET MVC源码分析系列

    Controller下的JsonResult的ExecuteResult方法 public override void ExecuteResult(ControllerContext context) ...

  7. Spring 源码分析衍生篇十 :Last-Modified 缓存机制

    文章目录 一.前言 二.Last-Modify 三.实现方案 1. 实现 org.springframework.web.servlet.mvc.LastModified接口 1.1. 简单演示 1. ...

  8. Lua源码分析 - 虚拟机篇 - 语义解析之Opcode执行(18)

    目录 一.虚拟机篇 - 指令执行状态机luaV_execute 二.虚拟机篇 - 状态机的具体实现原理 一.虚拟机篇 - 指令执行状态机luaV_execute 在<Lua源码分析 - 主流程篇 ...

  9. Spring MVC源码分析(一) 说明

    为什么会有这一个系列的文章 现在正值大学的第一个暑假,这个暑假我准备开始进入框架的学习,首先我选择的是Spring MVC框架,这是自己学的第一个框架,我在学习的过程中不断告诉自己,这一次不是单纯的学 ...

  10. ASP.NET MVC源码现在可以下载了(翻译)

    上个月我在blog里介绍了ASP.NET MVC Roadmap,两个周以前我们发布了ASP.NET Preview 2 Release,ASP.NET组的Phil Haack写了一篇很好的blog介 ...

最新文章

  1. Hyperledger Fabric(术语表)
  2. python语言接口_Python-接口自动化(一)
  3. 云计算数据管理的4个关键因素
  4. 设置组件局部样式原理-属性选择器
  5. 如何搭建lamp(CentOS7+Apache+MySQL+PHP)环境
  6. scrollview嵌套listview 滑动事件冲突的解决方法
  7. 寒门难再出贵子(6),一篇值得思考的文章
  8. 【鲲鹏HCIA考试】随堂习题卷四
  9. Ubuntu下的QQ-For-Linux 安装
  10. c语言 枚举大小写,C语言枚举类型(Enum)深入理解
  11. 年会互动游戏有哪些?年会微信互动游戏制作流程是什么?
  12. word怎么删除参考文献的横线_Word2010利用尾注做参考文献时如何删除尾注中的横线...
  13. c语言结构体应用例程:输入今天日期,输出明天日期
  14. linux源代码是用,阅读Linux源代码-使用lxr和glimpse
  15. nginx 之 http 转 https (两种方式)
  16. matlab中除法的使用,错误使用 / 矩阵维度必须一致
  17. 不会用matplotlib画多子图?收好这2个套路
  18. matlab图像增强实验总结,图像处理实验报告
  19. 腾讯优图NCNN详细分析及实践操作(含Yolov5实践)
  20. 行业研究报告-全球与中国电压变送器市场现状及未来发展趋势

热门文章

  1. C#: WinForm系列——DataGridView单元格文本自动换行
  2. jQuery调用或获取iframe中的方法或控件值
  3. Win8.1开机速度慢解决办法
  4. kotlin埋点_GitHub - shajinyang/ilvdo-event-track: 埋点框架
  5. 我的世界乘法计算机,《我的世界》计算器的加法和乘法器电路图文教程
  6. html mysql 数据列表_html的列表加载数据库
  7. HTML:HTML界面实现HTML代码编译运行界面
  8. Java编程:树(基础部分)
  9. Openlayer:学习笔记之控件
  10. 组建技术团队的一些思考