2010-02-22 4 views
5

J'ai un site MVC 2 (RC2) de base avec un contrôleur de base ("Home") et un domaine ("Admin") avec un contrôleur ("Résumé"). Lorsque j'appelle http://website/Abstract - le contrôleur abstrait dans la zone Admin est appelé même si je n'ai pas spécifié la zone dans l'URL. Pour aggraver les choses - il ne semble pas savoir qu'il est sous Admin parce qu'il ne peut pas trouver la vue associée et juste retourne:ASP.NET MVC 2 RC 2 renvoie Contrôleur de zone spécifique lorsqu'aucune zone n'est spécifiée

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 

Est-ce que je fais quelque chose de mal? Est-ce un bug? Une caractéristique?

+0

Que pensez-vous de cela: http://stackoverflow.com/questions/2314524/asp-net-mvc-2-rc-2-returns-area-specific-controller-when-no-area-specified Est-ce que haack dit essentiellement que mon problème est dû à la conception et que le seul moyen de le contourner est de router les routes vers tous les contrôleurs de l'espace de noms par défaut? – Bryan

+0

ci-dessus lien vers le commentaire de hack est faux. correct: http://stackoverflow.com/questions/1639971/mvc-2-arearegistration-routes-order/1640825#1640825 – Bryan

+0

Sans voir les routes que vous avez définies dans votre région et dans votre site principal, il est impossible de dire. – Haacked

Répondre

11

Mon ami et moi avons rencontré le même problème avec les zones dans ASP.NET MVC 2. Nous avons trouvé un « hack » qui, jusqu'à présent, semble fonctionner. Pour la version tl; dr, voir le bas de cette réponse.

Vous avez probablement quelque chose de semblable à ce qui suit dans votre « Admin » zone de la classe « AdminAreaRegistration.cs »:

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

Ainsi, il faut donner un sens que lorsque vous faites une demande de « http://website/Abstract » , la route "Admin_default" ne correspond pas à la demande. Ainsi, de par sa conception, le framework MVC tente de faire correspondre la requête à d'autres routes définies. Si vous avez utilisé l'outil MVC dans Visual Studio pour créer votre projet Web, une route "Default" sera définie dans votre fichier "Global.asax" (à la racine de votre projet Web). Il devrait ressembler à ceci:

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

La route « par défaut » réussit à faire correspondre la demande de « http://website/Abstract », avec « contrôleur » = « abstrait », « action » = « Index » (valeur par défaut), et "id" = UrlParameter.Optional (valeur par défaut). C'est le comportement correct et prévu ... jusqu'à présent.

Maintenant, l'infrastructure MVC tentera de charger le contrôleur "abstrait". De par sa conception, MVC recherchera une classe appelée "AbstractController" qui étend "Controller" n'importe où dans la hiérarchie des fichiers/espaces de noms du projet web. Il est important de noter que l'emplacement et l'espace de noms d'un contrôleur n'affectent pas la capacité de MVC à le trouver; en d'autres termes, juste parce que vous avez placé le "AbstractController" dans un dossier appelé "Areas \ Admin \ Controllers" et changé l'espace de noms en "Web.Areas.Admin.Controllers" au lieu de, disons, "Web.Controllers" , ne signifie pas que MVC ne l'utilisera pas. Lorsque MVC exécute l'action "Index" dans "AbstractController" qui, très probablement, renvoie juste "View()", MVC devient confus car il ne sait pas où trouver la vue "Index". Parce que MVC a correspondu à un itinéraire non-zone (la route "par défaut" dans Global.asax), il pense que la vue correspondante doit être située dans des dossiers de vue non-zone. Ainsi, vous obtenez le message d'erreur familier:

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 

Nous, comme vous, ne voulez pas les demandes de « http://website/Abstract » pour résoudre à « AbstractController » de la zone « Admin »; seul "http://website/Admin/Abstract" devrait fonctionner. Je ne peux pas penser à pourquoi quelqu'un voudrait ce comportement.

Une solution simple est de supprimer la route "par défaut" dans Global.asax, mais cela va casser tous les contrôleurs/vues non-zone réguliers. Ce n'est probablement pas une option pour la plupart des gens ...

Alors, nous avons pensé que nous pourrions limiter l'ensemble des contrôleurs que MVC utiliserait pour les demandes assorties par la voie « par défaut » dans 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 
    ); 
} 

Non. Une demande pour "http://website/Abstract" encore utilise "AbstractController" dans la zone "Admin", même si l'espace de noms "AbstractController" est "Web.Areas.Admin.Controllers" et (clairement) pas "Web.Controllers" . C'est complètement déroutant; il semble que cette liste blanche n'a aucun effet sur la résolution du contrôleur de MVC.

- tl; dr réponse commence ici -

Après quelques bidouillages, nous avons compris comment forcer MVC à utiliser uniquement les contrôleurs au sein de l'espace de noms liste blanche (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 
} 

Définir la clé "UseNamespaceFallback" du dictionnaire de DataTokens sur la route "par défaut" false. Maintenant, quand nous faisons une demande pour "http://website/Abstract", la route "Default" sera toujours correspondue (ceci est un comportement valide!) Mais MVC pas utiliser un contrôleur qui n'est pas dans les espaces de noms définis; dans ce cas, seuls les contrôleurs dans l'espace de noms "Web.Controllers" sont valides. Enfin, c'est la fonctionnalité que nous recherchions! Nous ne pouvons pas comprendre pourquoi ce n'est pas le comportement par défaut. Bizarre, hein?

Espérons que cela aide.

+0

merci pour la réponse détaillée. meilleure réponse que j'ai déjà vue. J'avais eu recours à des routes codées en dur pour tous mes contrôleurs de racine. – Bryan

+0

c'est une excellente réponse .. Je viens de rencontrer le même comportement et vraiment surpris avec ça, en fait. –

1

Avez-vous configuré votre itinéraire correctement? Lorsque vous utilisez des zones, vous devez modifier manuellement votre code de routage pour que MVC apparaisse dans les bons espaces de noms.

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

+0

L'article de Haack concerne principalement la résolution des problèmes liés aux noms de contrôleurs en double. J'ai essayé d'ajouter l'espace de nom du contrôleur par défaut à ma route par défaut, mais cela n'aide pas. Il semble y avoir une certaine confusion quant à ce que cela fait vraiment: http://stackoverflow.com/questions/721700/asp-net-mvc-controller-namespace-array Certaines personnes pensent qu'il donne juste la priorité à un certain espace de noms - mais tous les d'autres sont encore fouillés. – Bryan

Questions connexes