在ControllerBuilder類中設置ControllerFactory,而後使用ControllerFactory建立Controller。 http請求在進入httphandler映射處理時,經過ControllerBuilder的Current獲取ControllerFactory,而後使用默認或者註冊的(若是註冊地話)ControllerFactory建立controller。默認的工廠是一個DefaultControllerFactory對象,由下面代碼能夠看出。ide
internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver) { ControllerBuilder controllerBuilder = this; IResolver<IControllerFactory> resolver = serviceResolver; if (resolver == null) resolver = (IResolver<IControllerFactory>) new SingleServiceResolver<IControllerFactory>((Func<IControllerFactory>) (() => this._factoryThunk()),(IControllerFactory) new DefaultControllerFactory() { ControllerBuilder = this }, "ControllerBuilder.GetControllerFactory"); controllerBuilder._serviceResolver = resolver; }
而Controller的產生是經過DefaultControllerFactory的CreateController來實現的,代碼以下:函數
public virtual IController CreateController(RequestContext requestContext, string controllerName) { if (requestContext == null) throw new ArgumentNullException("requestContext"); if (string.IsNullOrEmpty(controllerName)) throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName"); Type controllerType = this.GetControllerType(requestContext, controllerName); return this.GetControllerInstance(requestContext, controllerType); }
而後查看GetControllerType方法:ui
protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName) { if (string.IsNullOrEmpty(controllerName)) throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName"); object obj; if (requestContext != null && requestContext.RouteData.DataTokens.TryGetValue("Namespaces", out obj)) { IEnumerable<string> enumerable = obj as IEnumerable<string>; if (enumerable != null && Enumerable.Any<string>(enumerable)) { HashSet<string> namespaces = new HashSet<string>(enumerable, (IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase); Type withinNamespaces = this.GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, namespaces); if (withinNamespaces != (Type) null || false.Equals(requestContext.RouteData.DataTokens["UseNamespaceFallback"])) return withinNamespaces; } } if (this.ControllerBuilder.DefaultNamespaces.Count > 0) { HashSet<string> namespaces = new HashSet<string>((IEnumerable<string>) this.ControllerBuilder.DefaultNamespaces, (IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase); Type withinNamespaces = this.GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, namespaces); if (withinNamespaces != (Type) null) return withinNamespaces; } return this.GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, (HashSet<string>) null); }
能夠看到最終都歸結到同一個方法GetControllerTypeWithinNamespaces中,代碼以下:this
private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces) { this.ControllerTypeCache.EnsureInitialized(this.BuildManager); ICollection<Type> controllerTypes = this.ControllerTypeCache.GetControllerTypes(controllerName, namespaces); switch (controllerTypes.Count) { case 0: return (Type) null; case 1: return Enumerable.First<Type>((IEnumerable<Type>) controllerTypes); default: throw DefaultControllerFactory.CreateAmbiguousControllerException(route, controllerName, controllerTypes); } }
而方法EnsureInitialized()是經過IBuildManager獲取程序中全部實現了IController的類型,而後在這些類型裏用路由數據或者ControllerBuilder中的命名空間和controller的名稱進行匹配,若是沒有匹配,返回null,若是有一個匹配,返回,若是有多個,拋出異常!url
如今獲取到了controllerType的類型,而後返回到工廠的CreateController的最後一步,查看GetControllerInstance方法,代碼以下:spa
protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType) { if (controllerType == (Type) null) { throw new HttpException(404, string.Format((IFormatProvider) CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_NoControllerFound, new object[1] { (object) requestContext.HttpContext.Request.Path })); } else { if (typeof (IController).IsAssignableFrom(controllerType)) return this.ControllerActivator.Create(requestContext, controllerType); throw new ArgumentException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_TypeDoesNotSubclassControllerBase, new object[1] { (object) controllerType }), "controllerType"); } }
能夠看到,這個時候又使用到了另一個對象ControllerActivator,由DefaultControllerFactory的構造函數能夠看出orm
internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver) { if (controllerActivator != null) this._controllerActivator = controllerActivator; else this._activatorResolver = activatorResolver ?? (IResolver<IControllerActivator>) new SingleServiceResolver<IControllerActivator>((Func<IControllerActivator>) (() => (IControllerActivator) null),(IControllerActivator) new DefaultControllerFactory.DefaultControllerActivator(dependencyResolver), "DefaultControllerFactory constructor"); }
默認使用的是實現了接口IResolver<TService>的SingleServiceResolver<TService>對象默認註冊的一個內部對象DefaultControllerActivator,而後調用它的create方法,代碼以下:xml
public IController Create(RequestContext requestContext, Type controllerType) { try { return (IController) (this._resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType)); } catch (Exception ex) { throw new InvalidOperationException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_ErrorCreatingController, new object[1] { (object) controllerType }), ex); } }
而DefaultControllerActivator對象中的屬性_resolverThunk是一個Func<IDependencyResolver> _resolverThunk委託對象,咱們經過DefaultControllerFactory構造函數中調用的new DefaultControllerFactory.DefaultControllerActivator(dependencyResolver),能夠看到DefaultControllerActivator的構造函數對象
public DefaultControllerActivator(IDependencyResolver resolver) { if (resolver == null) this._resolverThunk = (Func<IDependencyResolver>) (() => DependencyResolver.Current); else this._resolverThunk = (Func<IDependencyResolver>) (() => resolver); }
對它的設置,若是在本身實現的ControllerFactory的構造函數中傳遞了本身定義的一個IDependencyResolver對象或者DependencyResolver的SetResolver方法設置了一個自定義的IDependencyResolver對象,就會使用它,若是沒有,則使用默認的DependencyResolver.Current,能夠看到DependencyResolver.Current是一個實現了IDependencyResolver接口對象的引用,從他的構造函數blog
public DependencyResolver() { this.InnerSetResolver((IDependencyResolver) new DependencyResolver.DefaultDependencyResolver()); }
看出它使用的是一個內部私有的對象DefaultDependencyResolver,
private class DefaultDependencyResolver : IDependencyResolver { public object GetService(Type serviceType) { if (!serviceType.IsInterface) { if (!serviceType.IsAbstract) { try { return Activator.CreateInstance(serviceType); } catch { return (object) null; } } } return (object) null; } public IEnumerable<object> GetServices(Type serviceType) { return Enumerable.Empty<object>(); } }
它的GetService方法,經過反射建立了咱們須要的controller對象,由此,controller建立成功!
Area中controller的解析過程:
首先咱們知道,在程序剛啓動時,咱們會調用AreaRegistration.RegisterAllAreas()方法:
internal static void RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state) { foreach (Type type in TypeCacheUtil.GetFilteredTypesFromAssemblies("MVC-AreaRegistrationTypeCache.xml", new Predicate<Type>(AreaRegistration.IsAreaRegistrationType), buildManager)) ((AreaRegistration) Activator.CreateInstance(type)).CreateContextAndRegister(routes, state); }
它是先查找出程序中全部實現了AreaRegistration的區域對象,而後建立他們的實例,調用實例的CreateContextAndRegister方法,來建立AreaRegistrationContext對象,
internal void CreateContextAndRegister(RouteCollection routes, object state) { AreaRegistrationContext context = new AreaRegistrationContext(this.AreaName, routes, state); string @namespace = this.GetType().Namespace; if (@namespace != null) context.Namespaces.Add(@namespace + ".*"); this.RegisterArea(context); }
而後調用RegisterArea方法,對路由進行註冊,能夠看出,這個時候還作了一個額外的事情,就是給上下文的屬性Namespaces添加了一個以(區域註冊對象所在命名空間+".*")的命名空間,這個最後會用於解析controller對象,經過後續代碼能夠看出,這個上下文的Namespaces會被使用。
而通常的RegisterArea方法就是經過咱們本身建立的區域註冊對象來重寫實現的,是經過調用AreaRegistrationContext對象的MapRoute()方法來實現路由註冊的.
public Route MapRoute(string name, string url, object defaults, object constraints, string[] namespaces) { if (namespaces == null && this.Namespaces != null) namespaces = Enumerable.ToArray<string>((IEnumerable<string>) this.Namespaces); Route route = RouteCollectionExtensions.MapRoute(this.Routes, name, url, defaults, constraints, namespaces); route.DataTokens["area"] = (object) this.AreaName; bool flag = namespaces == null || namespaces.Length == 0; route.DataTokens["UseNamespaceFallback"] = (object) (bool) (flag ? 1 : 0); return route; }
這個方法中咱們看到若是註冊路由時沒有指定命名空間,則會把上下文的Namespaces屬性拿來使用,除了註冊路由以外,這個方法還作了一步工做,在路由數據的DataTokens中添加了一個以UseNamespaceFallback爲key的數據,它的值是經過判斷若是註冊路由的命名空間參數和上下文的Namespaces都爲空的狀況下,爲1,不然爲0;爲1,則在解析controller時須要使用controllerBuilder中的DefaultNamespaces屬性的值中的命名空間。這個邏輯咱們能夠再DefaultControllerFactory的GetControllerType()方法中能夠看到!
並且咱們能夠看到路由數據RouteData中表示區域的area的值是存在DataTokens屬性中