6

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

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

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

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

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

其次,在 MVC 框架中是否还有一个程序化的构造来代表一个区域?我似乎找不到一个。只有四种结构与区域相关

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

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

已编辑

我刚刚注意到MVC-AreaRegistrationTypeCache.xml在文件夹 \Windows\Microsoft.NET\Framework\v4.xx\Temporary ASP.NET Files\root\RandomlyGeneratedHash1\RandomlyGeneratedHash2\UserCache 中有这个文件被调用。

该文件夹有两个文件:

a) MVC-AreaRegistrationTypeCache.xml:该文件包含机器上所有具有区域的程序集中的所有区域的列表。

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

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

我在想这AreaRegistration门课可能是那个。进一步探索它...

4

3 回答 3

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()的调用调用 internal RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state),然后调用 internal CreateContextAndRegister(RouteCollection routes, object state),后者创建 AreaRegistrationContext 并将其传递给RegisterArea()

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

于 2010-09-01T16:36:10.543 回答
1

您可以做 MVC 正在做的事情,迭代所有引用的程序集并查找继承自AreaRegistration. 然后你可以简单地得到AreaRegistration.AreaName.

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

于 2012-03-06T08:50:08.313 回答
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;
}
于 2013-11-15T22:40:10.513 回答