2010-02-22 8 views
5

Ho un sito MVC 2 (RC2) di base con un controller di livello base ("Casa") e un'area ("Amministratore") con un controller ("Abstract"). Quando chiamo http://website/Abstract - il controller Abstract nell'area Admin viene chiamato anche se non ho specificato l'Area nell'URL. A peggiorare le cose - non sembra sapere che è sotto amministrazione, perché non riesce a trovare la vista associata e restituisce solo:ASP.NET MVC 2 RC 2 restituisce il controller specifico dell'area quando nessuna area specificata

The view 'Index' or its master was not found. The following locations were searched: 
~/Views/Abstract/Index.aspx 
~/Views/Abstract/Index.ascx 
~/Views/Shared/Index.aspx 
~/Views/Shared/Index.ascx 

sto facendo qualcosa di sbagliato? è un insetto? Una caratteristica?

+0

cosa ne pensate di questo: http://stackoverflow.com/questions/2314524/asp-net-mvc-2-rc-2-returns-area-specific-controller-when-no-area-specified è fondamentalmente un errore dire che il mio problema è di progettazione e l'unico modo per aggirarlo è quello di instradare il codice su ogni controller nello spazio dei nomi predefinito? – Bryan

+0

sopra il link al commento di haack è sbagliato. correggi uno: http://stackoverflow.com/questions/1639971/mvc-2-arearegistration-routes-order/1640825#1640825 – Bryan

+0

Senza vedere i percorsi che hai definito sia nella tua area che nel tuo sito principale, è impossibile raccontare. – Haacked

risposta

11

mio amico ed io stavano vivendo lo stesso problema con le aree in ASP.NET MVC 2. Abbiamo trovato un "hack" che, finora, sembra funzionare. Per la versione tl; dr, vedi la parte inferiore di questa risposta.

probabilmente si sono qualcosa di simile a quanto segue in classe "AdminAreaRegistration.cs" la vostra zona "Admin":

// Web/Areas/Admin/AdminAreaRegistration.cs 

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

Quindi, dovrebbe avere un senso che quando si effettua una richiesta per "http://website/Abstract" , la route "Admin_default" non corrisponde alla richiesta. Pertanto, in base alla progettazione, il framework MVC tenta di abbinare la richiesta a qualsiasi altra route definita. Se hai utilizzato gli strumenti MVC in Visual Studio per creare il tuo progetto web, avrai una route "predefinita" definita nel tuo file "Global.asax" (nella radice del tuo progetto web). Esso dovrebbe essere simile a questo:

// Web/Global.asax.cs 

public static void RegisterRoutes(RouteCollection routes) { 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     "Default", 
     "{controller}/{action}/{id}", 
     new {controller = "Home", action = "Index", id = UrlParameter.Optional} 
    ); 
} 

Il percorso "Default" riesce a corrispondenza alla richiesta di "http://website/Abstract", con =, "azione" "controller" "astratta" = "Index" (valore di default), e "id" = UrlParameter.Optional (valore predefinito). Questo è il comportamento corretto e inteso ... finora.

Ora, il framework MVC tenterà di caricare il controller "Astratto". In base alla progettazione, MVC cerca una classe denominata "AbstractController" che estende "Controller" ovunque all'interno della gerarchia di file/spazio dei nomi del progetto Web. È importante notare che l'ubicazione e lo spazio dei nomi di un controller non influiscono sulla capacità di MVC di trovarlo; in altre parole, solo perché hai inserito "AbstractController" all'interno di una cartella denominata "Aree \ Admin \ Controller" e modificato lo spazio dei nomi in "Web.Areas.Admin.Controllers" anziché, ad esempio, "Web.Controllers" , non significa che MVC non lo userà.

Quando MVC esegue l'azione "Index" in "AbstractController" che, molto probabilmente, solo restituisce "View()", quindi MVC si confonde perché non sa dove trovare l ' "Indice" vista. Poiché MVC ha trovato una corrispondenza non di area (la route "Predefinita" in Global.asax), ritiene che la vista corrispondente debba trovarsi nelle cartelle di visualizzazione non dell'area. Così si ottiene il messaggio di errore familiare:

The view 'Index' or its master was not found. The following locations were searched: 
~/Views/Abstract/Index.aspx 
~/Views/Abstract/Index.ascx 
~/Views/Shared/Index.aspx 
~/Views/Shared/Index.ascx 

Noi, proprio come voi, non volevi richieste di "http://website/Abstract" per risolvere a "AbstractController" "Admin" del territorio; solo "http://website/Admin/Abstract" dovrebbe funzionare. Non riesco a pensare perché qualcuno vorrebbe questo comportamento.

Una soluzione semplice consiste nell'eliminare la route "Predefinita" in Global.asax, ma in questo modo interromperà qualsiasi controller/vista normale non area. Questa probabilmente non è un'opzione per la maggior parte delle persone ...

Così, abbiamo pensato che avremmo potuto limitare il set di controllori che MVC avrebbe usato per richieste con corrispondenza per via "Default" in Global.asax:

// Web/Global.asax.cs 

public static void RegisterRoutes(RouteCollection routes) { 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     "Default", 
     "{controller}/{action}/{id}", 
     new {controller = "Home", action = "Index", id = UrlParameter.Optional}, 
     new[] {"Web.Controllers"} // Added this line 
    ); 
} 

Nope. Una richiesta per "http://website/Abstract" sarà ancora usa "AbstractController" nell'area "Admin", anche se lo spazio dei nomi di "AbstractController" è "Web.Areas.Admin.Controllers" e (chiaramente) non "Web.Controllers" . Questo è completamente confuso; sembra che questa white-list non abbia alcun effetto visibile sulla risoluzione del controller di MVC.

- tl; dr risposta inizia qui -

Dopo un po 'di hacking, abbiamo capito come forzare MVC utilizzare solo controllori all'interno del namespace (s) white list.

// Web/Global.asax.cs 

public static void RegisterRoutes(RouteCollection routes) { 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     "Default", 
     "{controller}/{action}/{id}", 
     new {controller = "Home", action = "Index", id = UrlParameter.Optional}, 
     new[] {"Web.Controllers"} 
    ).DataTokens["UseNamespaceFallback"] = false; // Added this line 
} 

impostare la chiave "UseNamespaceFallback" del dizionario DataTokens sulla rotta "Default" su false. Ora, quando facciamo una richiesta per "http://website/Abstract", la route "Default" sarà ancora abbinata (questo è un comportamento valido!) Ma MVC sarà non utilizzare qualsiasi Controller che non rientra nei namespace definiti; in questo caso, solo i controller all'interno dello spazio dei nomi "WebControllers" sono validi. Finalmente, questa è la funzionalità che stavamo cercando! Non riusciamo a capire perché questo non sia il comportamento predefinito. Strano, eh?

Spero che questo aiuti.

+0

grazie per la risposta dettagliata. migliore risposta che ho visto ancora. avevo fatto ricorso solo a percorsi hard-coding per tutti i miei controller di root. – Bryan

+0

questa è un'ottima risposta .. Ho appena incontrato lo stesso comportamento e davvero sorpreso, in realtà. –

1

Hai impostato correttamente il percorso? Quando si utilizzano le aree, è necessario modificare manualmente il codice di routing in modo che MVC guardi negli spazi dei nomi corretti.

http://haacked.com/archive/2010/01/12/ambiguous-controller-names.aspx

+0

L'articolo di Haack riguarda principalmente la risoluzione dei problemi relativi ai nomi dei controller duplicati. Ho provato a aggiungere lo spazio dei nomi del controller predefinito alla mia route predefinita, ma non aiuta. Sembra che ci sia un po 'di confusione su ciò che realmente fa: http://stackoverflow.com/questions/721700/asp-net-mvc-controller-namespace-array Alcune persone pensano che dia priorità a un determinato spazio dei nomi - ma tutto altri ancora vengono cercati. – Bryan

Problemi correlati