MVC5 Controller简要创建过程(2):由ControllerFactory创建Controller

上文已经完成了ControllerFactory的创建,接下来就是调用其CreateController()方法创建Controller了。

DefaultControllerFactory中CreateController()的实现:

        public virtual IController CreateController(RequestContext requestContext, string controllerName)

        {

            //...

            Type controllerType = GetControllerType(requestContext, controllerName); IController controller = GetControllerInstance(requestContext, controllerType); return controller;

        }

很明显,首先根据controllerName获得controller类型,再根据controller类型获得controller实例。

先看GetControllerType()方法:

 protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName)

        {

            RouteData routeData = requestContext.RouteData;

            if (routeData != null && routeData.HasDirectRouteMatch())

            {

                return GetControllerTypeFromDirectRoute(routeData);

            }



            // first search in the current route's namespace collection

            object routeNamespacesObj;

            Type match;

            if (routeData.DataTokens.TryGetValue(RouteDataTokenKeys.Namespaces, out routeNamespacesObj))

            {

                IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>;

                if (routeNamespaces != null && routeNamespaces.Any())

                {

                    HashSet<string> namespaceHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase);

                    match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceHash); // the UseNamespaceFallback key might not exist, in which case its value is implicitly "true"

                    if (match != null || false.Equals(routeData.DataTokens[RouteDataTokenKeys.UseNamespaceFallback]))

                    {

                        // got a match or the route requested we stop looking

                        return match;

                    }

                }

            }



            // then search in the application's default namespace collection

            if (ControllerBuilder.DefaultNamespaces.Count > 0)

            {

                HashSet<string> namespaceDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);

                match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceDefaults); if (match != null)

                {

                    return match;

                }

            }



            // if all else fails, search every namespace

            return GetControllerTypeWithinNamespaces(routeData.Route, controllerName, null /* namespaces */);

        }

关于DirectRouteMatch先留个坑,以后填。

首先根据当前路由的命名空间查找controller,如果查找失败,则查找当前ControllerBuilder的默认命名空间,最后查找每个命名空间。我们注意到这三个步骤都调用了GetControllerTypeWithinNamespaces()方法,那么它具体怎么实现呢?

以下既是GetControllerTypeWithinNamespaces()的具体实现:

private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces)

        {

            // Once the master list of controllers has been created we can quickly index into it

 ControllerTypeCache.EnsureInitialized(BuildManager); ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces); switch (matchingTypes.Count)

            {

                case 0:

                    // no matching types

                    return null;



                case 1:

                    // single matching type

                    return matchingTypes.First();



                default:

                    // multiple matching types

                    throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);

            }

        }

看来具体的查找又和一个ControllerTypeCache类型的对象有关,并且只在找到唯一controller类型时将它返回。

那么来看看ControllerTypeCache类型吧:

internal sealed class ControllerTypeCache

    {

        private volatile Dictionary<string, ILookup<string, Type>> _cache;

        private object _lockObj = new object();

        public void EnsureInitialized(IBuildManager buildManager)

        {

            if (_cache == null)

            {

                lock (_lockObj)

                {

                    if (_cache == null)

                    {

                        List<Type> controllerTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(TypeCacheName, IsControllerType, buildManager);

                        var groupedByName = controllerTypes.GroupBy(

                            t => t.Name.Substring(0, t.Name.Length - "Controller".Length),

                            StringComparer.OrdinalIgnoreCase);

                        _cache = groupedByName.ToDictionary(

                            g => g.Key,

                            g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),

                            StringComparer.OrdinalIgnoreCase);

                    }

                }

            }

        }



        public ICollection<Type> GetControllerTypes(string controllerName, HashSet<string> namespaces)

        {

            HashSet<Type> matchingTypes = new HashSet<Type>();



            ILookup<string, Type> namespaceLookup;

            if (_cache.TryGetValue(controllerName, out namespaceLookup))

            {

                // this friendly name was located in the cache, now cycle through namespaces

                if (namespaces != null)

                {

                    foreach (string requestedNamespace in namespaces)

                    {

                        foreach (var targetNamespaceGrouping in namespaceLookup)

                        {

                            if (IsNamespaceMatch(requestedNamespace, targetNamespaceGrouping.Key))

                            {

                                matchingTypes.UnionWith(targetNamespaceGrouping);

                            }

                        }

                    }

                }

                else

                {

                    // if the namespaces parameter is null, search *every* namespace

                    foreach (var namespaceGroup in namespaceLookup)

                    {

                        matchingTypes.UnionWith(namespaceGroup);

                    }

                }

            }



            return matchingTypes;

        }

        //...

)

 原来 EnsureInitialized()用来确保_cache被初始化,而_cache则是根据 buildManager.GetReferencedAssemblies()得到的所有引用的程序集,将程序集中所有controller取出并将contoller.Name去掉controller后缀作为键的字典类型,字典的值又是一个以controller所在Namespace为键,controller实际类型为值的Lookup类型。

接下来的GetControllerTypes()就很明显了,就是根据传来的controllerName和namespaces参数查找controller类型并返回。

至此我们便了解了获得controller类型的整个流程,接下来便是controller实例的创建了。

 GetControllerInstance()的实现很简单:

protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)

        {

            return ControllerActivator.Create(requestContext, controllerType);

        }

真正的实现还是在IControllerActivator类型实例的Create()方法中,先看下这个实例如何生成:

         private IResolver<IControllerActivator> _activatorResolver;

         private IControllerActivator _controllerActivator;

         internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver)

        {

            if (controllerActivator != null)

            {

                _controllerActivator = controllerActivator;

            }

            else

            {

                _activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>( () => null, new DefaultControllerActivator(dependencyResolver), "DefaultControllerFactory constructor");

            }

        }



        private IControllerActivator ControllerActivator

        {

            get

            {

                if (_controllerActivator != null)

                {

                    return _controllerActivator;

                }

                _controllerActivator = _activatorResolver.Current; return _controllerActivator;

            }

        }

这我们就很熟悉了--和之前ControllerFactory是一样的。

最后看一下默认ControllerActivator--DefaultControllerActivator的实现:

 private class DefaultControllerActivator : IControllerActivator

        {

            private Func<IDependencyResolver> _resolverThunk;

            public DefaultControllerActivator(IDependencyResolver resolver)

            {

                if (resolver == null)

                {

                    _resolverThunk = () => DependencyResolver.Current;

                }

                else

                {

                    _resolverThunk = () => resolver;

                }

            }



            public IController Create(RequestContext requestContext, Type controllerType)

            {return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));

            }

        }

没什么复杂的,也和之前创建ControllerFactory一样,默认实现为DefaultDependencyResolver中的GetService()方法:利用反射创建一个Controller。

public object GetService(Type serviceType)

            {

                // Since attempting to create an instance of an interface or an abstract type results in an exception, immediately return null

                // to improve performance and the debugging experience with first-chance exceptions enabled.

                if (serviceType.IsInterface || serviceType.IsAbstract)

                {

                    return null;

                }



                try

                {

                    return Activator.CreateInstance(serviceType);

                }

                catch

                {

                    return null;

                }

            }

至此,我们终于了解了一个Controller的全过程。

你可能感兴趣的:(controller)