zoukankan      html  css  js  c++  java
  • 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的相关所有信息。

  • 相关阅读:
    self 和 super 关键字
    NSString类
    函数和对象方法的区别
    求两个数是否互质及最大公约数
    TJU Problem 1644 Reverse Text
    TJU Problem 2520 Quicksum
    TJU Problem 2101 Bullseye
    TJU Problem 2548 Celebrity jeopardy
    poj 2586 Y2K Accounting Bug
    poj 2109 Power of Cryptography
  • 原文地址:https://www.cnblogs.com/ghhlyy/p/2913598.html
Copyright © 2011-2022 走看看