码迷,mamicode.com
首页 > Web开发 > 详细

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

时间:2015-06-27 01:12:47      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:

上文已经完成了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的全过程。

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

标签:

原文地址:http://www.cnblogs.com/chengs/p/4603469.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!