• mvc源码解析(8)ControllerDescriptor控制器描述对象


          在上一篇讲完Controller对象创建,我们知道Controller对象是在MvcHandler里面的ProcessRequest方法里面调用的ProcessRequestInit来完成的,因此所有的初始化工作准备完成之后,开始执行Controller的激活工作。Controller的激活执行的是接口IController里面的Execute方法,该方法定义如下:

      public interface IController {
            void Execute(RequestContext requestContext);
        }

    而最终的执行是在类Controller里面的ExecuteCore方法,该方法具体实现如下:

     protected override void ExecuteCore() {

                PossiblyLoadTempData();            

                try {                

                   string actionName = RouteData.GetRequiredString("action");                

                    if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {                    

                         HandleUnknownAction(actionName);}            

                     }finally {                

                         PossiblySaveTempData();            

                        }        

            }

     红色的代码InvokeAction是接口IActionInvoker里面的方法,该接口定义如下:

      public interface IActionInvoker {
            bool InvokeAction(ControllerContext controllerContext, string actionName);
        }

    类ControllerActionInvoker实现了该接口,InvokeAction方法具体实现如下:

     public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) {            

            //获取Controller和Action的描述对象            

            ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext);            

            ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName);            

            if (actionDescriptor != null) {                

                    FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);

                    try {                    

                      AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);                    

                      if (authContext.Result != null) {                                

                             InvokeActionResult(controllerContext, authContext.Result);                    

                          }                    

                        else {                        

                             if (controllerContext.Controller.ValidateRequest)

                               {                            

                                     ValidateRequest(controllerContext); 

                               }

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

                            ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);                                       

                            InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result);                    

                       }                

              }catch (ThreadAbortException) {throw;}                

                catch (Exception ex) { ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);                    

               if (!exceptionContext.ExceptionHandled) {throw;}                    

                    InvokeActionResult(controllerContext, exceptionContext.Result);                

                 }

            return true;            

           }

      return false;        

    }

    我们先来看看这一句代码:

     ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext); 

     GetControllerDescriptor()方法到底是获取什么对象?该方法实现如下:

    protected virtual ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext) {
                Type controllerType = controllerContext.Controller.GetType();
                ControllerDescriptor controllerDescriptor = DescriptorCache.GetDescriptor(controllerType, () => new ReflectedControllerDescriptor(controllerType));
                return controllerDescriptor;
            }

     从缓存中获取ControllerDescriptor对象,GetDescriptor()方法实现如下:

      public ControllerDescriptor GetDescriptor(Type controllerType, Func<ControllerDescriptor> creator) {
                return FetchOrCreateItem(controllerType, creator);
            }

     这其中涉及到的FetchOrCreateItem()方法如下:

     protected TValue FetchOrCreateItem(TKey key, Func<TValue> creator) {                       

                  _rwLock.EnterReadLock();            

                 try {                

                      TValue existingEntry;                

                         if (_cache.TryGetValue(key, out existingEntry)){return existingEntry;}            

                 }finally {_rwLock.ExitReadLock();}       

                TValue newEntry = creator();            

                _rwLock.EnterWriteLock();            

               try {                

                        TValue existingEntry;                

                        if (_cache.TryGetValue(key, out existingEntry)) {                                         

                                  return existingEntry;                

                      }

                      _cache[key] = newEntry;                

                     return newEntry;            

               }finally {

                             _rwLock.ExitWriteLock();            

                  }        

    }

     该方法实现缓存的原理较为简单,结合_cache的定义:

          private readonly Dictionary<TKey, TValue> _cache;

     我们可以知道先是在Dictionary字典中查看是否有要寻找的Key,有的话直接返回key对应的Value,如果没有,则将新的项插入到缓存中,以备下次调用。在上面的代码中获取的ControllerDescriptor对象其实是ReflectedControllerDescriptor对象,类ReflectedControllerDescriptor实现了抽象类ControllerDescriptor的方法。ReflectedControllerDescriptor类的构造函数如下:

     public ReflectedControllerDescriptor(Type controllerType) {

                _controllerType = controllerType;            

              _selector = new ActionMethodSelector(_controllerType);        

    }

     ActionMethodSelector()方法里面最终调用的是PopulateLookupTables():

     private void PopulateLookupTables() {            

          MethodInfo[] allMethods = ControllerType.GetMethods(BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public);            

          MethodInfo[] actionMethods = Array.FindAll(allMethods, IsValidActionMethod);

          AliasedMethods = Array.FindAll(actionMethods, IsMethodDecoratedWithAliasingAttribute);            

         NonAliasedMethods = actionMethods.Except(AliasedMethods).ToLookup(method => method.Name, StringComparer.OrdinalIgnoreCase);        

    }

    结合方法IsValidActionMethod(),该方法定义如下:

           private static bool IsValidActionMethod(MethodInfo methodInfo) {
                return !(methodInfo.IsSpecialName ||
                         methodInfo.GetBaseDefinition().DeclaringType.IsAssignableFrom(typeof(Controller)));
            }

    因此我们可以知道PopulateLookupTables就是获取到所有公有的Action方法,并将寻找到的Action方法分为有别名的Action和没有别名的Action。同时我们来看看ControllerDescriptor类里面的一些成员变量:

    public virtual string ControllerName {            

        get {string typeName = ControllerType.Name;                

            if (typeName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) {

                       return typeName.Substring(0, typeName.Length - "Controller".Length); 

                   }

                 return typeName;}        

             }

            public abstract Type ControllerType {get;}

            public virtual string UniqueId {get {return _uniqueId.Value;}}

        因此我们可以知道ControllerDescriptor用来描述某一个Controller的元数据,其中ControllerName表示Controller的名称,来源于路由信息,ControllerType之前我们已经讲过,表示路由的类型,说白了就是可以区分具体的Controller对象(包含了命名空间等信息)。string类型的UniqueId用于标识唯一的ControllerDescriptor对象。同时我们还应该注意到ControllerDescriptor里面还有两个十分重要的抽象方法:

    //ControllerDescriptor的FindAction方法根据指定的Controller上下文和名称得到相应的Action方法,返回的是用于描述Action方法的ActionDescriptor对象        

    public abstract ActionDescriptor FindAction(ControllerContext controllerContext, string actionName);        

    public abstract ActionDescriptor[] GetCanonicalActions();

     这两个方法都在ControllerDescriptor的实现类ReflectedControllerDescriptor里面进行了重写,我们先来看看FindAction()方法的具体实现:

    public override ActionDescriptor FindAction(ControllerContext controllerContext, string actionName) {            

                MethodInfo matched = _selector.FindActionMethod(controllerContext, actionName);            

                if (matched == null) {return null;}

                return new ReflectedActionDescriptor(matched, actionName, this);         }

    里面最终调用的就是ReflectedActionDescriptor这个类的构造函数:

     internal ReflectedActionDescriptor(MethodInfo methodInfo, string actionName, ControllerDescriptor controllerDescriptor, bool validateMethod) {            

                if (validateMethod) {string failedMessage = VerifyActionMethodIsCallable(methodInfo);}

                MethodInfo = methodInfo;            

                _actionName = actionName;            

               _controllerDescriptor = controllerDescriptor;            

              _uniqueId = new Lazy<string>(CreateUniqueId);        

    }

    GetCanonicalActions()方法就是获取到Controller上的所有的公有的Action方法。这个获取Controller上的Action方法是有一些限制的,这些限制在VerifyActionMethodIsCallable方法有说明:1:不能是静态的方法;2:不能是继承自基类的方法,3:不能是开放的泛型类型参数;4:方法的参数中不能有ref和out修饰。

     internal static string VerifyActionMethodIsCallable(MethodInfo methodInfo) {            

          // we can't call static methods            

           if (methodInfo.IsStatic) {return String.Format(CultureInfo.CurrentCulture,MvcResources.ReflectedActionDescriptor_CannotCallStaticMethod,methodInfo,methodInfo.ReflectedType.FullName);}

         // we can't call instance methods where the 'this' parameter is a type other than ControllerBase            

          if (!typeof(ControllerBase).IsAssignableFrom(methodInfo.ReflectedType)) {return String.Format(CultureInfo.CurrentCulture,MvcResources.ReflectedActionDescriptor_CannotCallInstanceMethodOnNonControllerType, methodInfo,methodInfo.ReflectedType.FullName);}

        // we can't call methods with open generic type parameters            

             if (methodInfo.ContainsGenericParameters) {return String.Format(CultureInfo.CurrentCulture, MvcResources.ReflectedActionDescriptor_CannotCallOpenGenericMethods,methodInfo, methodInfo.ReflectedType.FullName);}

       // we can't call methods with ref/out parameters            

         ParameterInfo[] parameterInfos = methodInfo.GetParameters();            

         foreach (ParameterInfo parameterInfo in parameterInfos) {

              if (parameterInfo.IsOut || parameterInfo.ParameterType.IsByRef) {return String.Format(CultureInfo.CurrentCulture, MvcResources.ReflectedActionDescriptor_CannotCallMethodsWithOutOrRefParameter,methodInfo, methodInfo.ReflectedType.FullName, parameterInfo); } }

       //we can call this method            

          return null;

    }

        上面的废话讲了那么多,其实我们只要了解ControllerDescriptor里面包含着什么样的信息即可,如上面红色的语言所讲,说白了就是某一个Controller的包装类,里面包含有关Controller的相关所有信息。

  • 相关阅读:
    selenium登录百度
    selenium登录实验楼
    selenium登录慕课网
    selenium登录4399
    Python中的inf与nan
    Python—推导式
    vacode 精选插件(只为更舒心的编程)
    PHPStudy_pro 根目录下访问查看目录文件
    Thinkphp5 auto权限
    ThinkPHP admin.php后台登录
  • 原文地址:https://www.cnblogs.com/ghhlyy/p/2913598.html
Copyright © 2020-2023  润新知