探索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.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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM