2009-10-28 16 views
12

Ho notato che in MVC 2 Preview 2, AreaRegistration sta caricando i percorsi per ogni area in un ordine arbitrario. C'è un buon modo per prenderne uno prima dell'altro?MVC 2 AreaRegistration Routes Order

Ad esempio, ho due aree: "Sito" e "Amministratore". Entrambi hanno un controller "Blog".

Vorrei la seguente:

/admin/ --> go to Admin's Blog controller 
/  --> go to Site's Blog controller. 

Il problema è che si sta caricando il percorso del primo sito, quindi è la corrispondenza {controller}/{action}/{id} invece di admin/{controller}/{action}/{id} quando vado a l'URL "/ admin /". Quindi ottengo un 404, perché non ci sono controller Admin nell'area "Sito".

Entrambe le aree predefinite per il controller "Blog". Mi rendo conto che potrei semplicemente mettere site/{controller}/... come l'url, ma preferirei averlo alla radice se possibile. Ho anche provato a mantenere la rotta predefinita nella funzione RegisterRoutes globale, tuttavia, non viene quindi inviata all'area "Siti".

Grazie in anticipo!

risposta

7

Attualmente non è possibile ordinare le aree. Tuttavia, penso che abbia senso cercare di rendere ogni area più indipendente possibile da altre aree in modo che l'ordine non contenga.

Ad esempio, invece di avere il percorso predefinito {controller}/{action}/{id}, è possibile sostituirlo con percorsi specifici per ciascun controller. Oppure aggiungi un vincolo a quella rotta predefinita.

Stiamo rimuginando le opzioni per consentire l'ordine, ma non vogliamo complicare eccessivamente la funzionalità.

+0

Hey Phil, grazie per la spiegazione. Alla fine ho spostato il mio "sito" fuori dalle aree e ora è la sezione "predefinita/non area" (con viste e controllori in root). Quindi ho impostato il mio parametro namespace sui controller predefiniti per evitare l'errore "controller ambiguo". Inoltre, avrei potuto probabilmente impostare dei vincoli su qualcosa come^((?! Admin). *) Per ignorare l'amministratore nelle rotte dell'area del sito. Sono d'accordo, aggiungere più complessità non è grande, anche se sembra che le rotte di mvc 1 (non area) possano potenzialmente basarsi pesantemente sull'ordine. Grazie! – Jason

+0

Il processo di instradamento in genere dipende dall'ordine delle regole, quindi la funzione di 'ordinare' potrebbe essere importante. – twk

+0

Si prega di vedere la mia risposta per due tecniche che consentono di ordinare la registrazione dell'area (e quindi i loro percorsi) in qualsiasi ordine. – Eilon

30

Oltre a ciò che Haacked ha detto, è molto possibile ordinare le registrazioni di area (e quindi le loro rotte). Tutto quello che devi fare è registrare ogni area manualmente, nell'ordine che vuoi. Non è elegante come chiamare RegisterAllAreas() ma è sicuramente fattibile.

protected void Application_Start() { 
    var area1reg = new Area1AreaRegistration(); 
    var area1context = new AreaRegistrationContext(area1reg.AreaName, RouteTable.Routes); 
    area1reg.RegisterArea(area1context); 

    var area2reg = new Area2AreaRegistration(); 
    var area2context = new AreaRegistrationContext(area2reg.AreaName, RouteTable.Routes); 
    area2reg.RegisterArea(area2context); 

    var area3reg = new Area3AreaRegistration(); 
    var area3context = new AreaRegistrationContext(area3reg.AreaName, RouteTable.Routes); 
    area3reg.RegisterArea(area3context); 
} 

Un'altra opzione è quella di prendere il codice per RegisterAllAreas(), copiarlo nella vostra app, e costruire il proprio meccanismo per determinare l'ordine. È un bel po 'di codice da copiare se si desidera tutta la logica di caching di fantasia che fa il metodo built-in, ma la tua app potrebbe non averne nemmeno bisogno.

+0

Ottima risposta. Inoltre, meno codice se si effettua un metodo e quindi è una riga di codice per area. – CRice

4

Faccio questa soluzione:

AreaUtils.cs

using System; 
    using System.Web.Mvc; 
    using System.Web.Routing; 

    namespace SledgeHammer.Mvc.Site 
    { 
     public static class Utils 
     { 
       public static void RegisterArea<T>(RouteCollection routes, 
    object state) where T : AreaRegistration 

      { 
       AreaRegistration registration = 
    (AreaRegistration)Activator.CreateInstance(typeof(T)); 

        AreaRegistrationContext context = 
    new AreaRegistrationContext(registration.AreaName, routes, state); 

        string tNamespace = registration.GetType().Namespace; 
        if (tNamespace != null) 
       { 
        context.Namespaces.Add(tNamespace + ".*"); 
       } 

       registration.RegisterArea(context); 
      } 
     } 

    } 

In global.asax:

Utils.RegisterArea<SystemAreaRegistration>(RouteTable.Routes, null); 
Utils.RegisterArea<ClientSitesAreaRegistration>(RouteTable.Routes, null); 

//AreaRegistration.RegisterAllAreas(); do not dublicate register areas 

Nessuna modifica requred al codice di registrazione zona generato. Uso anche il constrant personalizzato nelle route per filtrare i percorsi per tipo di dominio in richiesta (dominio di sistema o sito utente).

Questo è il mio registrazioni zona come ad esempio:

namespace SledgeHammer.MVC.Site.Areas.System 
{ 
    public class SystemAreaRegistration : AreaRegistration 
    { 
     public override string AreaName 
     { 
      get { return "System"; } 
     } 

     public override void RegisterArea(AreaRegistrationContext context) 
     { 
      context.MapRoute(
       "System_Feedback", 
       "Feedback", 
       new { controller = "Feedback", action = "Index" } 
      ); 
      context.MapRoute(
       "System_Information", 
       "Information/{action}/{id}", 
       new { controller = "Information", action = "Index", id = UrlParameter.Optional } 
      ); 
     } 
    } 
} 



namespace SledgeHammer.MVC.Site.Areas.ClientSites 
{ 
    public class ClientSitesAreaRegistration : AreaRegistration 
    { 
     public override string AreaName 
     { 
      get { return "ClientSites"; } 
     } 

     public override void RegisterArea(AreaRegistrationContext context) 
     { 
      context.MapRoute(
       "ClientSites_default", 
       "{controller}/{action}/{id}", 
       new { controller = "Site", action = "Index", id = UrlParameter.Optional }, 
       new { Host = new SiteInGroups("clients") } 
      ); 
     } 
    } 
} 
+0

la tua classe util è fantastica perché indica che è necessario aggiungere lo spazio dei nomi per le aree altrimenti le rotte non saranno collegate ai controller –

4

Per riferimento,

In MVC3 (non so su MVC2) quando si desidera solo per mappare root per una specifica area/controller che si potrebbe semplicemente utilizzare una rotta globale. Basta ricordare di specificare lo spazio dei nomi/area.

routes.MapRoute(
     "CatchRoot", "", 
     new { controller = "SITEBLOG-CONTROLLER-NAME", action = "Index"} 
    ).DataTokens.Add("area", "SITE-AREA-NAME"); 
+0

+1 - Questa è una soluzione piacevole perché consente di raggruppare tutto in aree ma una area per servire come il catch-all con un URL più pulito. –

+0

Funziona perfettamente! Mi consente di avere tutti i controller in aree anziché "speciali" e aree reali. Per chiunque desideri lo stesso, registra il percorso predefinito in route config. – FDIM