你的位置:首页 > ASP.net教程

[ASP.net教程]探索RegisterAllAreas


在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.", 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)