2010-09-01 9 views
6

¿Hay alguna manera de obtener los nombres de las áreas en un proyecto de MVC?Obtener áreas asociadas con un proyecto de MVC

Aquí hay algunas maneras que se me ocurren:

a) Si tuviera la fuente, que podría navegar a través de la estructura de carpetas de proyectos y enumerar las carpetas en la carpeta Áreas. Pero eso no garantizaría que todas las carpetas representen áreas a menos que también haya enumerado la carpeta Controladores y Vistas debajo de cada una de las subcarpetas. Este enfoque, como puedes ver, apesta.

b) Del binario, podría enumerar todos los espacios de nombres que coincidan con los criterios RootNamespaceOfProject.Areas.*.

O, estoy seguro de que hay una manera más elegante. Debe haber algún diccionario en el marco ASP.NET MVC que mantiene un registro de todas las áreas.

En segundo lugar, ¿existe también una construcción programática en el marco de MVC que representa un área? Parece que no puedo encontrar uno. Sólo hay cuatro construcciones que son relacionada a las áreas:

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

Si existiera, sería posible, por ejemplo, para enumerar todos los controladores dentro de esa área?

Editado

Acabo de notar que existe este archivo llamado MVC-AreaRegistrationTypeCache.xml en la carpeta \ Windows \ Microsoft.NET \ Framework \ v4.x.x \ Temporary ASP.NET Files \ root \ RandomlyGeneratedHash1 \ RandomlyGeneratedHash2 \ UserCache.

Esta carpeta tiene dos archivos:

a) MVC-AreaRegistrationTypeCache.xml: Este archivo tiene la lista de todas las áreas en todas las asambleas en la máquina que tiene áreas.

b) MVC-ControllerTypeCache.xml: Este archivo enumera los controladores dentro de las áreas de los conjuntos.

Ahora, lo único que debe averiguar es si hay alguna forma programática para que MVC Framework lea estos archivos y diga si existe un área determinada en un archivo binario.

Estoy pensando que la clase AreaRegistration podría ser la indicada. Explorando más ...

+0

Ambas ideas son soluciones sin salida, ya que dependen de algo que no se puede controlar. Las áreas se pueden colocar en cualquier lugar de la estructura del proyecto, siempre que estén registradas y mapeadas. –

Respuesta

6

Parece que la única forma en que podrá recuperar las rutas registradas en su proyecto es enumerando el proyecto para los tipos que heredan el Registro de área, no parece haber ningún objeto privado o público que rastrea las áreas actualmente registradas.

larga explicación sigue ...

Un obstáculo a tener en cuenta aquí es que las zonas son poco más que un acoplamiento entre una cadena arbitraria y una lista de espacios de nombres. Cuando se registra un área, simplemente se extiende la colección de rutas para la aplicación con algunas nuevas reglas identificables por un único "área" DataToken.

Si observa el proceso para registrar un área, debe heredar de System.Web.Mvc.AreaRegistration y anular RegisterArea().RegisterArea() recibe un AreaRegistrationContext que define un nombre de área, colección de ruta y estado de objeto, pero si observa el formato para implementar RegisterArea(), devuelve vacío y no hace nada para preservar el objeto de contexto. Además, si observa el código que se ejecuta antes de que se active (Reflector) RegisterArea(), puede ver que el objeto AreaRegistrationContext que se pasa a RegisterArea() nunca se rastrea permanentemente.

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

Como se puede ver, una llamada al método estático RegisterAllAreas() invoca el RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state) interna, que a su vez llama a la CreateContextAndRegister(RouteCollection routes, object state) interno, que crea el AreaRegistrationContext y lo pasa a RegisterArea().

Por lo que puedo decir, nunca, en ningún momento, se crea el AreaRegistrationContext para cada área almacenada permanentemente.

+0

Spot on, Nathan! Noté lo mismo. Muchas gracias. Entonces, podría obtener todos los tipos que se derivan de Registro de área y luego comparar el valor de la propiedad AreaName del objeto con el nombre del área que estoy buscando. ¡Estupendo! Lo malo es que realmente no existe una asignación entre un área y sus controladores que se conserva en cualquier lugar. –

+0

@Water Cooler Puede analizar Routes.RouteCollection y comprobar los "espacios de nombres" DataToken (cadena []) de cada ruta y comparar esos valores con los espacios de nombres de todos sus controladores registrados. Tengo curiosidad por saber cuál es el uso previsto de esta funcionalidad, ya que puede haber una opción mejor que no se haya explorado. –

1

Puede hacer lo que hace MVC, iterar todos los ensamblados a los que se hace referencia y buscar clases que hereden de AreaRegistration. Entonces simplemente puede obtener el AreaRegistration.AreaName.

Estoy planeando hacer esto para construir mi barra de navegación de nivel superior utilizando Twitter Bootstrap.

+0

¿Cómo se repiten todos los ensamblados a los que se hace referencia? – awe

+0

Algo como 'new [] {Assembly.GetExecutingAssembly()} .Concat (Assembly.GetExecutingAssembly.GetReferencedAssemblies());' –

+1

Puede usar AppDomain.CurrentDomain.GetAssemblies() para obtener todo lo que pienso –

1

Este tema fue útil para encontrar la respuesta, pero nadie aquí lo publicó explícitamente. Esto es lo que se me ocurrió, pero tenga en cuenta que puede necesitar ajustarlo dependiendo de si todas sus áreas están en el mismo conjunto.

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; 
} 
Cuestiones relacionadas