Получить области, связанные с проектом MVC - PullRequest
6 голосов
/ 01 сентября 2010

Есть ли способ узнать названия областей в проекте MVC?

Вот несколько способов, которые я могу придумать:

a) Если бы у меня был источник, я мог бы просмотреть структуру папок проекта и перечислить папки в папке Области. Но это не гарантировало бы, что все папки представляют области, если бы я не перечислил папку Controllers и Views в каждой из подпапок. Этот подход, как вы можете сказать, отстой.

b) Из двоичного файла я мог бы перечислить все пространства имен, которые соответствуют критериям RootNamespaceOfProject.Areas.*.

Или, я уверен, есть более элегантный способ. В структуре ASP.NET MVC должен быть некоторый словарь, который ведет учет всех областей.

Во-вторых, есть ли программная конструкция в структуре MVC, которая представляет область? Кажется, я не могу его найти. Есть только четыре конструкции, которые связаны с областями:

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

Если бы он был, можно ли, скажем, перечислить все контроллеры в этой области?

1020 * Отредактированный *

Я только что заметил, что этот файл называется MVC-AreaRegistrationTypeCache.xml в папке \ Windows \ Microsoft.NET \ Framework \ v4.x.x \ Временные файлы ASP.NET \ root \ RandomlyGeneratedHash1 \ RandomlyGeneratedHash2 \ UserCache.

В этой папке два файла:

a) MVC-AreaRegistrationTypeCache.xml : этот файл содержит список всех областей во всех сборках на машине, которые имеют области.

b) MVC-ControllerTypeCache.xml : в этом файле перечислены контроллеры в областях сборок.

Теперь, единственное, что нужно выяснить, - это если какой-то программный способ заставить среду MVC прочитать эти файлы и сказать мне, существует ли определенная область в двоичном файле.

Я думаю, что класс AreaRegistration может быть единственным. Исследуя это дальше ...

Ответы [ 3 ]

6 голосов
/ 01 сентября 2010

Может показаться, что единственный способ получить маршруты, зарегистрированные в вашем проекте, - это перечислить проект для типов, которые наследуют AreaRegistration, и, по-видимому, нет ни одного частного или общедоступного объекта, который отслеживал бы зарегистрированные в данный момент области.

Далее следует длинное объяснение ...

Здесь следует помнить, что области представляют собой нечто большее, чем просто связь между произвольной строкой и списком пространств имен.Когда область регистрируется, она просто расширяет коллекцию маршрутов для приложения некоторыми новыми правилами, которые можно идентифицировать с помощью уникальной «области» DataToken.

Если вы посмотрите на процесс регистрации области, вы должны наследовать от System.Web.Mvc.AreaRegistration и переопределить RegisterArea () .RegisterArea () получает AreaRegistrationContext , который определяет имя области, коллекцию маршрутов и состояние объекта, но если вы наблюдаете формат для реализации RegisterArea (), он возвращает void и ничего не делает для сохранения объекта контекста.Более того, если вы посмотрите на код, который выполняется до того, как RegisterArea () запущен (Reflector), вы увидите, что объект AreaRegistrationContext, который передается в RegisterArea (), никогда не отслеживается постоянно.

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

AsВы можете видеть, что вызов статического метода RegisterAllAreas () вызывает внутренний RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state), который затем вызывает внутренний CreateContextAndRegister(RouteCollection routes, object state), который создает AreaRegistrationContext и передает его RegisterArea().

Насколько я могу судить, никогда, ни в коем случае, AreaRegistrationContext не создается для каждой области, сохраняемой постоянно.

1 голос
/ 16 ноября 2013

Эта тема помогла найти ответ, но никто здесь явно не опубликовал его. Вот то, что я придумал, но учтите, что вам может потребоваться настроить его в зависимости от того, все ли области находятся в одной сборке.

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;
}
1 голос
/ 06 марта 2012

Вы можете делать то, что делает MVC, выполнять итерацию всех сборок, на которые ссылаются, и искать классы, которые наследуются от AreaRegistration.Тогда вы можете просто получить AreaRegistration.AreaName.

Я планирую сделать это, чтобы построить мою панель навигации верхнего уровня с помощью Twitter Bootstrap.

...