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绑定获取前提条件,这个后面我们将详细介绍。

posted @ 2013-02-19 13:35  肖&申&克  阅读(363)  评论(0编辑  收藏  举报