在MVC中注冊Area時,我們一般會在相應的區域下定義一個繼承與AreaRegistration的類,代碼如下:
public class AdminAreaRegistration : AreaRegistration { public override string AreaName { get { return "Admin"; } } public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( "Admin_default", "Admin/{controller}/{action}/{id}", new { action = "Index", id = UrlParameter.Optional } ); } }
那么問題來了,類AdminAreaRegistration是在什么時候被實例化的,方法RegisterArea是何時被調用的?
1、Global中注冊所有區域
AreaRegistration.RegisterAllAreas();
2、查看AreaRegistration.RegisterAllAreas源碼
internal static void RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state) { //從緩存以及組件中查找所有的AreaRegistration List<Type> filteredTypesFromAssemblies = TypeCacheUtil.GetFilteredTypesFromAssemblies("MVC-AreaRegistrationTypeCache.xml", new Predicate<Type>(AreaRegistration.IsAreaRegistrationType), buildManager); foreach (Type current in filteredTypesFromAssemblies) { AreaRegistration areaRegistration = (AreaRegistration)Activator.CreateInstance(current); areaRegistration.CreateContextAndRegister(routes, state); } }
3、從緩存及引用程序集中查找Type
public static List<Type> GetFilteredTypesFromAssemblies(string cacheName, Predicate<Type> predicate, IBuildManager buildManager) { TypeCacheSerializer serializer = new TypeCacheSerializer(); //從緩存中查找AreaRegistration List<Type> list = TypeCacheUtil.ReadTypesFromCache(cacheName, predicate, buildManager, serializer); if (list != null) { return list; } //從組件中查找AreaRegistration list = TypeCacheUtil.FilterTypesInAssemblies(buildManager, predicate).ToList<Type>(); //添加緩存 TypeCacheUtil.SaveTypesToCache(cacheName, list, buildManager, serializer); return list; }
4、從程序集中查找Type
private static IEnumerable<Type> FilterTypesInAssemblies(IBuildManager buildManager, Predicate<Type> predicate) { IEnumerable<Type> enumerable = Type.EmptyTypes; //獲取所有被引用的組件 ICollection referencedAssemblies = buildManager.GetReferencedAssemblies(); foreach (Assembly assembly in referencedAssemblies) { Type[] types; try { //獲取組件中的所有類型 types = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { types = ex.Types; } enumerable = enumerable.Concat(types); } //返回所有類型中的AreaRegistration return from type in enumerable where TypeCacheUtil.TypeIsPublicClass(type) && predicate(type) select type; }
5、此處使用predicate(type),不得不回到步驟2看看傳入的是啥
private static bool IsAreaRegistrationType(Type type) { return typeof(AreaRegistration).IsAssignableFrom(type) && type.GetConstructor(Type.EmptyTypes) != null; }
6、此時已找到所有的AreaRegistration類,再次回到步驟2,創建AreaRegistration實例,並調用方法RegisterArea
internal void CreateContextAndRegister(RouteCollection routes, object state) { AreaRegistrationContext areaRegistrationContext = new AreaRegistrationContext(this.AreaName, routes, state); string @namespace = base.GetType().Namespace; if (@namespace != null) { areaRegistrationContext.Namespaces.Add(@namespace + ".*"); } this.RegisterArea(areaRegistrationContext); }
由以上代碼可以看書,方法RegisterAllAreas就是簡單粗暴的將所有引用程序集中的類型遍歷一遍,找到所有的AreaRegistration,並調用注冊區域方法。
為了驗證以上觀點,特做了以下測試。
新建一個類庫程序,並在類庫程序中注冊區域,觀察是否注冊成功。文件結構如下

測試結果:

由於本人也是最近才接觸MVC,在學習過程中碰到一些問題,特此備注
1、Mvc定義區域外層文件夾約定為Areas
2、Views文件夾下一定要有web.config,否則會報錯(當前上下文中不存在名稱“ViewBag”),可以復制項目Views下自動生成的Web.config
3、注冊區域可以在其他被引用的項目中(AreaRegistration)
