2010-09-01 15 views
6

C'è un modo per ottenere i nomi delle aree in un progetto MVC?Ottieni aree associate a un progetto MVC

Ecco alcuni modi che posso pensare:

a) Se avessi la fonte, ho potuto sfogliare la struttura di cartelle di progetto ed enumerare le cartelle nella cartella Zone. Ma ciò non garantisce che tutte le cartelle rappresentino le aree a meno che non abbia anche elencato la cartella Controllers and Views in ciascuna delle sottocartelle. Questo approccio, come puoi capire, fa schifo.

b) Dal binario, è possibile enumerare tutti gli spazi dei nomi che corrispondono ai criteri RootNamespaceOfProject.Areas.*.

Oppure, sono sicuro che c'è un modo più elegante. Ci deve essere un dizionario nel framework MVC di ASP.NET che tiene traccia di tutte le aree.

In secondo luogo, esiste anche un costrutto programmatico nel framework MVC che rappresenta un'area? Non riesco a trovarne uno. Ci sono solo quattro costrutti che sono correlata sul territorio nazionale:

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

Se ci fosse uno, sarebbe possibile, ad esempio, per enumerare tutti i controller all'interno di quella zona?

A cura

Ho appena notato che c'è questo file chiamato MVC-AreaRegistrationTypeCache.xml nella cartella \ Windows \ Microsoft.NET \ Framework \ v4.x.x \ Temporary ASP.NET Files \ root \ RandomlyGeneratedHash1 \ RandomlyGeneratedHash2 \ UserCache.

Questa cartella non contiene due file:

a) MVC-AreaRegistrationTypeCache.xml: Questo file ha l'elenco di tutte le aree in tutte le assemblee sulla macchina che hanno aree.

b) MVC-ControllerTypeCache.xml: questo file elenca i controller all'interno delle aree degli assiemi.

Ora, l'unica cosa da scoprire è se c'è un modo programmatico per far sì che il framework MVC legga questi file e mi dica se esiste una certa area in un binario.

Sto pensando che la classe AreaRegistration potrebbe essere quella. Esplorandolo ulteriormente ...

+0

Entrambe queste idee sono soluzioni non vincenti in quanto dipendono da qualcosa che non hai modo di controllare! Le aree possono essere posizionate ovunque nella struttura del progetto, purché siano registrate e mappate. –

risposta

6

Sembrerebbe che l'unico modo per recuperare le rotte registrate nel progetto sia enumerando il progetto per i tipi che ereditano l'AreaRegistration, non sembra che vi sia alcun oggetto privato o pubblico che tiene traccia delle aree attualmente registrate.

lunga spiegazione segue ...

Un ostacolo da tenere a mente è che le aree sono poco più di un accoppiamento tra una stringa arbitraria e un elenco di spazi dei nomi. Quando un'area è registrata, si tratta semplicemente di estendere la raccolta del percorso per l'applicazione con alcune nuove regole identificabili da un DataToken "area" unico.

Se si osserva il processo per la registrazione di un'area, è necessario ereditare da System.Web.Mvc.AreaRegistration e sostituire RegisterArea().RegisterArea() riceve un AreaRegistrationContext che definisce un nome di area, una raccolta di percorsi e uno stato di oggetto, ma se si osserva il formato per l'implementazione di RegisterArea(), restituisce nulla e non fa nulla per preservare l'oggetto di contesto. Inoltre, se si guarda il codice che viene eseguito prima che RegisterArea() venga attivato (Reflector), è possibile vedere che l'oggetto AreaRegistrationContext che viene passato a RegisterArea() non viene mai tracciato in modo permanente.

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

Come si può vedere, una chiamata al metodo statico RegisterAllAreas() invoca l'interno RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state), che poi chiama il interna CreateContextAndRegister(RouteCollection routes, object state), che crea l'AreaRegistrationContext e lo passa al RegisterArea().

Per quanto ne so, mai, in nessun punto, AreaRegistrationContext è stato creato per ogni area memorizzata in modo permanente.

+0

Spot on, Nathan! Ho notato la stessa cosa. Grazie mille. Quindi, è possibile ottenere tutti i tipi derivati ​​da AreaRegistration e quindi confrontare il valore della proprietà AreaName dell'oggetto con il nome dell'area che sto cercando. Grande! La cosa brutta è che non c'è davvero alcuna mappatura tra un'area e i suoi controllori che è preservata ovunque. –

+0

@Water Cooler È possibile analizzare Route.RouteCollection e controllare il DataToken "Namespace" (stringa []) di ogni percorso e confrontare tali valori con gli spazi dei nomi di tutti i controller registrati. Sono curioso di sapere quale sia l'uso previsto di questa funzionalità in quanto potrebbe esserci un'opzione migliore che non è stata esplorata. –

1

Si può fare ciò che MVC sta facendo, iterare tutti gli assembly di riferimento e cercare le classi che ereditano da AreaRegistration. Quindi puoi semplicemente ottenere lo AreaRegistration.AreaName.

Sto pensando di farlo per creare la mia barra di navigazione di primo livello utilizzando Twitter Bootstrap.

+0

Come si iterano tutti gli assiemi di riferimento? – awe

+0

Qualcosa come 'new [] {Assembly.GetExecutingAssembly()} .Concat (Assembly.GetExecutingAssembly.GetReferencedAssemblies());' –

+1

Puoi usare AppDomain.CurrentDomain.GetAssemblies() per ottenere tutto ciò che penso –

1

Questo thread è stato utile per trovare la risposta, ma nessuno qui lo ha pubblicato esplicitamente. Ecco cosa mi è venuto in mente, ma tieni presente che potrebbe essere necessario regolarlo a seconda che tutte le aree siano nello stesso assembly.

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; 
} 
Problemi correlati