获取与MVC项目关联的区域

时间:2010-09-01 15:56:45

标签: asp.net-mvc-2 asp.net-mvc-areas

有没有办法可以获得MVC项目中区域的名称?

以下是我能想到的几种方式:

a)如果我有源,我可以浏览项目文件夹结构并枚举Areas文件夹下的文件夹。但这并不能保证所有文件夹都代表区域,除非我还枚举了每个子文件夹下的Controllers and Views文件夹。你可以说,这种方法很糟糕。

b)从二进制文件中,我可以枚举符合条件RootNamespaceOfProject.Areas.*的所有名称空间。

或者,我确信这是一种更优雅的方式。 ASP.NET MVC框架中必须有一些字典可以记录所有区域。

其次,MVC框架中是否还有一个代表区域的程序化构造?我好像找不到一个。区域中只有四个相关的构造:

 1. AreaRegistration
 2. AreaRegistrationContext
 3. IRouteWithArea
 4. AreaHelpers (an internal class)

如果有的话,是否有可能枚举该区域内的所有控制器?

被修改

我刚注意到文件夹\ Windows \ Microsoft.NET \ Framework \ v4.x.x \ Temporary ASP.NET Files \ root \ RandomlyGeneratedHash1 \ RandomlyGeneratedHash2 \ UserCache中有一个名为MVC-AreaRegistrationTypeCache.xml的文件。

此文件夹有两个文件:

a) MVC-AreaRegistrationTypeCache.xml :此文件包含计算机上所有区域中包含区域的所有区域的列表。

b) MVC-ControllerTypeCache.xml :此文件列出了程序集区域内的控制器。

现在,唯一要知道的是,是否有一些编程方式让MVC框架读取这些文件并告诉我二进制文件中是否存在某个区域。

我在想AreaRegistration类可能就是那个。进一步探索......

3 个答案:

答案 0 :(得分:6)

您似乎能够检索项目中注册的路由的唯一方法是枚举项目以继承AreaRegistration的类型,似乎没有任何私有或公共对象跟踪当前注册的区域。

很长的解释如下......

这里要记住的一个障碍是,区域只不过是任意字符串和命名空间列表之间的耦合。当一个区域被注册时,它只是扩展了应用程序的路径集合,其中一些新规则可由唯一的“区域”DataToken识别。

如果您查看注册区域的过程,则必须从System.Web.Mvc.AreaRegistration继承并覆盖RegisterArea()。 RegisterArea()接收一个AreaRegistrationContext,它定义了一个区域名称,路径集合和对象状态,但是如果你观察到实现RegisterArea()的格式,它会返回void并且不会保留上下文对象。更重要的是,如果查看在触发RegisterArea()之前运行的代码(Reflector),您可以看到传递给RegisterArea()的AreaRegistrationContext对象永远不会被永久跟踪。

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);
    }
}

internal void CreateContextAndRegister(RouteCollection routes, object state)
{
    AreaRegistrationContext context = new AreaRegistrationContext(this.AreaName, routes, state);
    string str = base.GetType().Namespace;
    if (str != null)
    {
        context.Namespaces.Add(str + ".*");
    }
    this.RegisterArea(context);
}

正如您所看到的,对静态方法RegisterAllAreas()的调用会调用内部RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state),然后调用内部CreateContextAndRegister(RouteCollection routes, object state),它会创建AreaRegistrationContext并将其传递给{{1 }}。

据我所知,在任何时候,永远不会为永久存储的每个区域创建AreaRegistrationContext。

答案 1 :(得分:1)

您可以执行MVC正在执行的操作,迭代所有引用的程序集并查找从AreaRegistration继承的类。然后,您只需获取AreaRegistration.AreaName

我打算使用Twitter Bootstrap构建我的顶级导航栏。

答案 2 :(得分:1)

此主题有助于找到答案,但此处没有人明确发布。这是我想出的,但请注意,您可能需要根据所有区域是否在同一个组件中进行调整。

private IEnumerable<AreaRegistration> GetAllAreasRegistered()
{
    var assembly = this.GetType().Assembly;
    var areaTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(AreaRegistration)));
    var areas = new List<AreaRegistration>();
    foreach (var type in areaTypes)
    {
        areas.Add((AreaRegistration)Activator.CreateInstance(type));
    }
    return areas;
}