上文已经完成了ControllerFactory的创建,接下来就是调用其CreateController()方法创建Controller了。
public virtual IController CreateController(RequestContext requestContext, string controllerName) { //... Type controllerType = GetControllerType(requestContext, controllerName); IController controller = GetControllerInstance(requestContext, controllerType); return controller; }
很明显,首先根据controllerName获得controller类型,再根据controller类型获得controller实例。
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()方法,那么它具体怎么实现呢?
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类型时将它返回。
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实例的创建了。
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是一样的。
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的全过程。