2010-02-22 6 views
5

Ich habe einen Basis-MVC 2 (RC2) Standort mit einem Basiscontroller ("Home") und einem Bereich ("Admin") mit ein Controller ("Abstract"). Wenn ich http://website/Abstract rufe - wird der Abstract-Controller im Admin-Bereich aufgerufen, obwohl ich den Bereich in der URL nicht angegeben habe. Um die Sache noch schlimmer - es scheint nicht zu wissen, dass es unter Admin ist, weil es nicht die zugehörige Ansicht finden und einfach zurückgibt:ASP.NET MVC 2 RC 2 gibt bereichsspezifischen Controller zurück, wenn kein Bereich angegeben wurde

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 

Bin ich etwas falsch? Ist das ein Fehler? Eine Eigenschaft?

+0

was denken Sie alle darüber: http://stackoverflow.com/questions/2314524/asp-net-mvc-2-rc-2-returns-area-specific-controller-when-no-are-specified ist im Grunde gesagt, mein Problem ist von Entwurf und der einzige Weg, um es ist hart Routen zu jedem Controller im Standard-Namespace zu codieren? – Bryan

+0

über den Link zu Hayacks Kommentar ist falsch. Korrektes: http://stackoverflow.com/questions/1639971/mvc-2-arearegistration-routes-order/1640825#1640825 – Bryan

+0

Ohne die Routen zu sehen, die Sie sowohl in Ihrer Region als auch auf Ihrer Hauptseite definiert haben, ist dies unmöglich sagen. – Haacked

Antwort

11

Mein Freund und ich waren erleben das gleiche Problem mit Areas in ASP.NET MVC 2. Wir sind ein „Hack“ herausgefunden, dass, so weit scheint zu funktionieren. Für die tl; dr-Version, siehe den unteren Teil dieser Antwort.

Sie haben wahrscheinlich etwas Ähnliches wie die folgenden in Ihrem „Admin“ Gegend „AdminAreaRegistration.cs“ Klasse:

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

So sollte es Sinn machen, dass, wenn Sie machen einen Antrag auf „http://website/Abstract“ , die Route "Admin_default" stimmt nicht mit der Anfrage überein. Aus diesem Grund versucht das MVC-Framework die Anforderung mit anderen definierten Routen abzugleichen. Wenn Sie die MVC-Tools in Visual Studio zum Erstellen Ihres Webprojekts verwendet haben, wird in Ihrer Datei "Global.asax" (im Stammverzeichnis Ihres Webprojekts) eine "Standardroute" definiert. Es sollte so aussehen:

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

Die "Default" Route erfolgreich für "http://website/Abstract" die Anforderung in passenden, mit "Controller" = "Zusammenfassung", "Aktion" = "Index" (Standardwert), und "id" = UrlParameter.Optional (Standardwert). Das ist das richtige und beabsichtigte Verhalten ... so weit.

Nun versucht das MVC-Framework, den "Abstract" -Controller zu laden. Von Entwurf wird MVC nach einer Klasse suchen, die "AbstractController" aufgerufen wird, die "Controller" irgendwo innerhalb der Datei-/Namespacehierarchie des Webprojekts erweitert. Es ist wichtig zu beachten, dass der Speicherort und der Namespace eines Controllers die Fähigkeit von MVC nicht beeinflussen, es zu finden. mit anderen Worten, nur weil Sie den "AbstractController" in einem Ordner namens "Areas \ Admin \ Controllers" platziert haben und den Namespace in "Web.Areas.Admin.Controllers" anstatt in "Web.Controllers" geändert haben. , bedeutet nicht, dass MVC es nicht verwenden wird.

Wenn MVC die Aktion "Index" in "AbstractController" ausführt, die höchstwahrscheinlich nur "View()" zurückgibt, wird MVC verwirrt, weil es nicht weiß, wo die "Index" -Ansicht zu finden ist. Da MVC eine Nicht-Bereichsroute zugeordnet hat (die "Standardroute" in Global.asax), sollte die übereinstimmende Ansicht in Nicht-Bereichsansichtsordnern gespeichert sein. So erhalten Sie die bekannte Fehlermeldung:

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 

Wir, so wie Sie, nicht-Anfragen wollten für „http://website/Abstract“ zu lösen, um „Admin“ Gegend „AbstractController“; nur "http://website/Admin/Abstract" sollte funktionieren. Ich kann mir nicht vorstellen, warum jemand dieses Verhalten möchte.

Eine einfache Lösung ist das Löschen der "Standard" Route in Global.asax, , aber Dies wird alle regulären Nicht-Bereich Controller/Ansichten zu brechen. Dies ist wahrscheinlich keine Option für die meisten Leute ...

Also, wir dachten, dass wir den Satz von Controller beschränken könnte, die MVC für Anfragen der "Default" Route in Global.asax abgestimmt verwenden würde:

// 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. Eine Anfrage für "http://website/Abstract" wird noch verwenden "AbstractController" innerhalb der "Admin" Bereich, obwohl der "AbstractController" Namespace ist "Web.Areas.Admin.Controllers" und (klar) nicht "Web.Controllers" . Das ist gründlich verwirrend; Es sieht so aus, als hätte diese Whitelist keine Auswirkungen auf die Controller-Auflösung von MVC.

- tl; dr Antwort hier beginnt -

Nach einigem Hacking, haben wir herausgefunden, wie MVC nur zu zwingen Controller zu verwenden, in der weißen Liste Namespace (s).

// 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 
} 

den "UseNamespaceFallback" Schlüssel des DataTokens Wörterbuch An der "Default" Route falsch. Wenn wir jetzt eine Anfrage für "http://website/Abstract" stellen, wird die "Standard" -Route immer noch übereinstimmen (dies ist ein gültiges Verhalten!), Aber MVC wird nicht irgendeinen Controller verwenden, der nicht innerhalb der definierten Namespaces liegt; In diesem Fall sind nur die Controller im Namespace "Web.Controllers" gültig. Schließlich ist dies die Funktionalität, nach der wir gesucht haben! Wir können nicht herausfinden, warum dies nicht das Standardverhalten ist. Seltsam, nicht wahr?

Hoffe, das hilft.

+0

danke für die detaillierte Antwort. beste Antwort, die ich bisher gesehen habe. Ich hatte nur auf hart codierende Routen zu all meinen Root-Controllern zurückgegriffen. – Bryan

+0

das ist eine tolle Antwort .. Ich habe gerade das gleiche Verhalten und wirklich überrascht damit, eigentlich. –

1

Haben Sie Ihr Routing richtig eingerichtet? Wenn Sie Bereiche verwenden, müssen Sie Ihren Routing-Code manuell ändern, damit MVC in den richtigen Namespaces sucht.

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

+0

In Haacks Artikel geht es hauptsächlich darum, Probleme mit doppelten Controllernamen aufzuklären. Ich habe versucht, den Standard-Controller-Namespace zu meiner Standardroute hinzuzufügen, aber das hilft nicht. Es scheint einige Verwirrung darüber zu geben, was das wirklich bewirkt: http://stackoverflow.com/questions/721700/asp-net-mvc-controller-namespace-array Manche Leute denken, dass es nur einem bestimmten Namensraum Priorität gibt - aber alle Andere werden immer noch gesucht. – Bryan