• mvc源码解读(10)ParameterDescriptor方法Action方法的参数描述对象


       前面两篇文章中我们已经大概的讲解了一下ControllerDescriptor和ActionDescriptor这两个分别对应Controller和Action的描述对象,已经大概的知道他们包含的信息了。这篇文章我们将根据mvc3的源码继续往下看,在ControllerActionInvoker类中的InvokeAction方法中通过FindAction获取到ActionDescriptor之后,直接将代码贴上来吧:

    跳过中间的那些代码(稍后补充上),直接看这一句:

     IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);

    GetParameterValues方法具体实现如下:

     //数据参数绑定包装类        

    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;        

    }

    我们可以看到红色代码中GetParameters方法就是返回一个ParameterDescriptor对象,而GetParameters我们在讲ActionDescriptor的时候就已经说了一下,它最终调用的是ReflectedActionDescriptor里面的LazilyFetchParametersCollection方法:

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

    ReflectedParameterDescriptor的构造函数如下:

    public ReflectedParameterDescriptor(ParameterInfo parameterInfo, ActionDescriptor actionDescriptor) {

                ParameterInfo = parameterInfo;            

                _actionDescriptor = actionDescriptor;            

               _bindingInfo = new ReflectedParameterBindingInfo(parameterInfo);        

    }

    这里面同时又涉及到一个ReflectedParameterBindingInfo类,该类的构造函数如下:

     public ReflectedParameterBindingInfo(ParameterInfo parameterInfo) {
                _parameterInfo = parameterInfo;
                ReadSettingsFromBindAttribute();
            }

    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;        

    }

     这里涉及到的密封类BindAttribute继承自Attribute,顾名思义就是获取应用在方法参数上的自定义特性。BindAttribute的有如下成员:

           public string Exclude {

                 get {return _exclude ?? String.Empty; }

                 set {_exclude = value; _excludeSplit = AuthorizeAttribute.SplitString(value); }        

               }

            public string Include {

                     get {return _include ?? String.Empty; }

                     set {_include = value;_includeSplit = AuthorizeAttribute.SplitString(value); }        

             }

            public string Prefix {get;set;}

            internal static bool IsPropertyAllowed(string propertyName, string[] includeProperties, string[] excludeProperties) {            

                bool includeProperty = (includeProperties == null) || (includeProperties.Length == 0) || includeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);            

                bool excludeProperty = (excludeProperties != null) && excludeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);            

               return includeProperty && !excludeProperty;         }

    }

     IsPropertyAllowed方法表示指定的属性是否要用于绑定。因此我们回到ReflectedParameterDescriptor这个类的BindingInfo属性:

    private readonly ReflectedParameterBindingInfo _bindingInfo; 

    public override ParameterBindingInfo BindingInfo {
                get {
                    return _bindingInfo;
                }
            }

           这样我们可以得知ReflectedParameterDescriptor的BindingInfo的Include、Exclude和Prefix属性对应的就是BindAttribute里面的相关属性。分别表示是否显示自己设置的绑定,不绑定的属性名称,Prefix表示绑定的参数属性的前缀名称。因为参数绑时在请求中数据都是带有类名作为前缀的。再回到上面的ReflectedParameterBindingInfo集成自抽象类ParameterBindingInfo,该类有如下成员:

     public abstract class ParameterBindingInfo {

            public virtual IModelBinder Binder {get {return null;}}

            public virtual ICollection<string> Exclude {get {return new string[0];}}

            public virtual ICollection<string> Include {get {return new string[0];}}

            public virtual string Prefix {get {return null; }}

     属性Exclude,Include和Prefix都被子类ReflectedParameterBindingInfo重写了,我们主要看红色的代码,接口IModelBinder的定义如下:

      public interface IModelBinder {
            object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
        }

     接口里面的BindModel方法就是整个mvc的模型绑定的核心,通过以上分析我们可以知道,无论是ControllerDescriptor,ActionDescriptor还是ParameterDescriptor都是为Model绑定获取前提条件,这个后面我们将详细介绍。

  • 相关阅读:
    Sqlite官方的查询优化文档
    VC++动态链接库(DLL)编程深入浅出(三)转
    用Python查询手机号码归属地
    Delphi使用迅雷的开放下载引擎下载
    Android基础之一
    VC++动态链接库深入浅出(转)
    在Python脚本中使用Delphi控件
    Python与其他语言结合的参数转换函数PyArg_ParseTuple()
    设计模式之模板方法模式(Template)
    设计模式之简单工厂模式(Simple Factory)
  • 原文地址:https://www.cnblogs.com/ghhlyy/p/2916509.html
Copyright © 2020-2023  润新知