Comment définir une route par défaut (vers une zone) dans MVC

Ok, cela a déjà été demandé, mais il n’ya pas de solution solide. Donc, pour moi-même et pour les autres qui pourraient trouver cela utile.

Dans MVC2 (ASP.NET), je le souhaite. Lorsque quelqu’un navigue sur le site Web, une zone par défaut est spécifiée. Donc, naviguer sur mon site devrait vous envoyer à ControllerX ActionY dans AreaZ.

Utiliser la route suivante dans le Global.asax

routes.MapRoute( "Area", "", new { area = "AreaZ", controller = "ControllerX ", action = "ActionY " } ); 

Maintenant, cela fonctionne comme s’il essayait de servir la bonne page. Cependant, MVC procède à la recherche de la vue à la racine du site et non dans le dossier Area.

y a-il un moyen de résoudre cela?

MODIFIER

Il existe une «solution» et, dans ControllerX, ActionY renvoie le chemin complet de la vue. Peu de piratage mais ça marche. Cependant, j’espère qu’il y a une meilleure solution.

  public ActionResult ActionY() { return View("~/Areas/AreaZ/views/ActionY.aspx"); } 

Modifier:

Cela devient également un problème lorsque vous avez un HTML ActionLink de la page. Si la zone n’est pas définie, le lien d’action est vide.

Est-ce que tout cela est conçu ou un défaut?

Celui-ci m’intéressait et j’ai finalement eu l’occasion de l’examiner. D’autres personnes n’ont apparemment pas compris qu’il s’agissait d’un problème pour trouver la vue , pas un problème avec le routage lui-même – et c’est probablement parce que le titre de votre question indique qu’il s’agit de routage.

Dans tous les cas, car il s’agit d’un problème lié à View, le seul moyen d’obtenir ce que vous voulez est de remplacer le moteur de vue par défaut . Normalement, lorsque vous faites cela, c’est simplement pour changer de moteur de vue (Spark, NHaml, etc.). Dans ce cas, ce n’est pas la logique de création de vues que nous devons remplacer, mais les méthodes FindPartialView et FindView de la classe VirtualPathProviderViewEngine .

Vous pouvez remercier vos stars que ces méthodes sont en fait virtuelles, car tout le rest dans VirtualPathProviderViewEngine n’est même pas accessible – c’est privé, et cela rend très ennuyeux de remplacer la logique de recherche car vous devez essentiellement réécrire la moitié du code qui est déjà été écrit si vous voulez qu’il joue bien avec le cache d’emplacement et les formats d’emplacement. Après avoir creusé dans Reflector, j’ai finalement réussi à trouver une solution de travail.

Ce que j’ai fait ici est de créer d’abord un AreaAwareViewEngine abstrait qui dérive directement de VirtualPathProviderViewEngine au lieu de WebFormViewEngine . Je l’ai fait pour que, si vous voulez créer des vues Spark (ou autre), vous pouvez toujours utiliser cette classe comme type de base.

Le code ci-dessous est assez long, pour vous donner un bref résumé de ce qu’il fait: Il vous permet de placer un {2} dans le format de l’emplacement, qui correspond au nom de la zone, de la même manière {1} correspond à le nom du contrôleur. C’est tout! C’est ce que nous avons dû écrire tout ce code pour:

BaseAreaAwareViewEngine.cs

 public abstract class BaseAreaAwareViewEngine : VirtualPathProviderViewEngine { private static readonly ssortingng[] EmptyLocations = { }; public override ViewEngineResult FindView( ControllerContext controllerContext, ssortingng viewName, ssortingng masterName, bool useCache) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (ssortingng.IsNullOrEmpty(viewName)) { throw new ArgumentNullException(viewName, "Value cannot be null or empty."); } ssortingng area = getArea(controllerContext); return FindAreaView(controllerContext, area, viewName, masterName, useCache); } public override ViewEngineResult FindPartialView( ControllerContext controllerContext, ssortingng partialViewName, bool useCache) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (ssortingng.IsNullOrEmpty(partialViewName)) { throw new ArgumentNullException(partialViewName, "Value cannot be null or empty."); } ssortingng area = getArea(controllerContext); return FindAreaPartialView(controllerContext, area, partialViewName, useCache); } protected virtual ViewEngineResult FindAreaView( ControllerContext controllerContext, ssortingng areaName, ssortingng viewName, ssortingng masterName, bool useCache) { ssortingng controllerName = controllerContext.RouteData.GetRequiredSsortingng("controller"); ssortingng[] searchedViewPaths; ssortingng viewPath = GetPath(controllerContext, ViewLocationFormats, "ViewLocationFormats", viewName, controllerName, areaName, "View", useCache, out searchedViewPaths); ssortingng[] searchedMasterPaths; ssortingng masterPath = GetPath(controllerContext, MasterLocationFormats, "MasterLocationFormats", masterName, controllerName, areaName, "Master", useCache, out searchedMasterPaths); if (!ssortingng.IsNullOrEmpty(viewPath) && (!ssortingng.IsNullOrEmpty(masterPath) || ssortingng.IsNullOrEmpty(masterName))) { return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this); } return new ViewEngineResult( searchedViewPaths.Union(searchedMasterPaths)); } protected virtual ViewEngineResult FindAreaPartialView( ControllerContext controllerContext, ssortingng areaName, ssortingng viewName, bool useCache) { ssortingng controllerName = controllerContext.RouteData.GetRequiredSsortingng("controller"); ssortingng[] searchedViewPaths; ssortingng partialViewPath = GetPath(controllerContext, ViewLocationFormats, "PartialViewLocationFormats", viewName, controllerName, areaName, "Partial", useCache, out searchedViewPaths); if (!ssortingng.IsNullOrEmpty(partialViewPath)) { return new ViewEngineResult(CreatePartialView(controllerContext, partialViewPath), this); } return new ViewEngineResult(searchedViewPaths); } protected ssortingng CreateCacheKey(ssortingng prefix, ssortingng name, ssortingng controller, ssortingng area) { return ssortingng.Format(CultureInfo.InvariantCulture, ":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}:", base.GetType().AssemblyQualifiedName, prefix, name, controller, area); } protected ssortingng GetPath(ControllerContext controllerContext, ssortingng[] locations, ssortingng locationsPropertyName, ssortingng name, ssortingng controllerName, ssortingng areaName, ssortingng cacheKeyPrefix, bool useCache, out ssortingng[] searchedLocations) { searchedLocations = EmptyLocations; if (ssortingng.IsNullOrEmpty(name)) { return ssortingng.Empty; } if ((locations == null) || (locations.Length == 0)) { throw new InvalidOperationException(ssortingng.Format("The property " + "'{0}' cannot be null or empty.", locationsPropertyName)); } bool isSpecificPath = IsSpecificPath(name); ssortingng key = CreateCacheKey(cacheKeyPrefix, name, isSpecificPath ? ssortingng.Empty : controllerName, isSpecificPath ? ssortingng.Empty : areaName); if (useCache) { ssortingng viewLocation = ViewLocationCache.GetViewLocation( controllerContext.HttpContext, key); if (viewLocation != null) { return viewLocation; } } if (!isSpecificPath) { return GetPathFromGeneralName(controllerContext, locations, name, controllerName, areaName, key, ref searchedLocations); } return GetPathFromSpecificName(controllerContext, name, key, ref searchedLocations); } protected ssortingng GetPathFromGeneralName(ControllerContext controllerContext, ssortingng[] locations, ssortingng name, ssortingng controllerName, ssortingng areaName, ssortingng cacheKey, ref ssortingng[] searchedLocations) { ssortingng virtualPath = ssortingng.Empty; searchedLocations = new ssortingng[locations.Length]; for (int i = 0; i < locations.Length; i++) { if (string.IsNullOrEmpty(areaName) && locations[i].Contains("{2}")) { continue; } string testPath = string.Format(CultureInfo.InvariantCulture, locations[i], name, controllerName, areaName); if (FileExists(controllerContext, testPath)) { searchedLocations = EmptyLocations; virtualPath = testPath; ViewLocationCache.InsertViewLocation( controllerContext.HttpContext, cacheKey, virtualPath); return virtualPath; } searchedLocations[i] = testPath; } return virtualPath; } protected string GetPathFromSpecificName( ControllerContext controllerContext, string name, string cacheKey, ref string[] searchedLocations) { string virtualPath = name; if (!FileExists(controllerContext, name)) { virtualPath = string.Empty; searchedLocations = new string[] { name }; } ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath); return virtualPath; } protected string getArea(ControllerContext controllerContext) { // First try to get area from a RouteValue override, like one specified in the Defaults arg to a Route. object areaO; controllerContext.RouteData.Values.TryGetValue("area", out areaO); // If not specified, try to get it from the Controller's namespace if (areaO != null) return (string)areaO; string namespa = controllerContext.Controller.GetType().Namespace; int areaStart = namespa.IndexOf("Areas."); if (areaStart == -1) return null; areaStart += 6; int areaEnd = namespa.IndexOf('.', areaStart + 1); string area = namespa.Substring(areaStart, areaEnd - areaStart); return area; } protected static bool IsSpecificPath(string name) { char ch = name[0]; if (ch != '~') { return (ch == '/'); } return true; } } 

Maintenant, comme indiqué, ce n'est pas un moteur concret, vous devez donc le créer également. Heureusement, cette partie est beaucoup plus facile, il suffit de définir les formats par défaut et de créer les vues:

AreaAwareViewEngine.cs

 public class AreaAwareViewEngine : BaseAreaAwareViewEngine { public AreaAwareViewEngine() { MasterLocationFormats = new ssortingng[] { "~/Areas/{2}/Views/{1}/{0}.master", "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.master", "~/Areas/{2}/Views/Shared/{0}.cshtml", "~/Views/{1}/{0}.master", "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.master" "~/Views/Shared/{0}.cshtml" }; ViewLocationFormats = new ssortingng[] { "~/Areas/{2}/Views/{1}/{0}.aspx", "~/Areas/{2}/Views/{1}/{0}.ascx", "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.aspx", "~/Areas/{2}/Views/Shared/{0}.ascx", "~/Areas/{2}/Views/Shared/{0}.cshtml", "~/Views/{1}/{0}.aspx", "~/Views/{1}/{0}.ascx", "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.aspx" "~/Views/Shared/{0}.ascx" "~/Views/Shared/{0}.cshtml" }; PartialViewLocationFormats = ViewLocationFormats; } protected override IView CreatePartialView( ControllerContext controllerContext, ssortingng partialPath) { if (partialPath.EndsWith(".cshtml")) return new System.Web.Mvc.RazorView(controllerContext, partialPath, null, false, null); else return new WebFormView(controllerContext, partialPath); } protected override IView CreateView(ControllerContext controllerContext, ssortingng viewPath, ssortingng masterPath) { if (viewPath.EndsWith(".cshtml")) return new RazorView(controllerContext, viewPath, masterPath, false, null); else return new WebFormView(controllerContext, viewPath, masterPath); } } 

Notez que nous avons ajouté peu d'entrées au standard ViewLocationFormats . Ce sont les nouvelles entrées {2} , où le {2} sera mappé à la area nous avons placée dans RouteData . J'ai laissé les MasterLocationFormats seuls, mais vous pouvez évidemment changer cela si vous le souhaitez.

Modifiez maintenant votre global.asax pour enregistrer ce moteur de vue:

Global.asax.cs

 protected void Application_Start() { RegisterRoutes(RouteTable.Routes); ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new AreaAwareViewEngine()); } 

... et enregistrez la route par défaut:

 public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Area", "", new { area = "AreaZ", controller = "Default", action = "ActionY" } ); routes.MapRoute( "Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "" } ); } 

Maintenant, créez le AreaController nous venons de référencer:

DefaultController.cs (dans ~ / Controllers /)

 public class DefaultController : Controller { public ActionResult ActionY() { return View("TestView"); } } 

Evidemment, nous avons besoin de la structure des répertoires et de la vue pour aller avec, nous allons garder cela très simple:

TestView.aspx (dans ~ / Areas / AreaZ / Views / Default / ou ~ / Areas / AreaZ / Views / Shared /)

 < %@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %> 

TestView

This is a test view in AreaZ.

Et c'est tout. Enfin, nous avons terminé .

Pour la plupart, vous devriez être capable de prendre simplement BaseAreaAwareViewEngine et AreaAwareViewEngine et de le déposer dans n'importe quel projet MVC, même si cela AreaAwareViewEngine beaucoup de code, il vous suffit de l'écrire une seule fois. Après cela, il suffit de modifier quelques lignes dans global.asax.cs et de créer la structure de votre site.

C’est comme ça que je l’ai fait. Je ne sais pas pourquoi MapRoute () ne vous permet pas de définir la zone, mais renvoie l’object route afin que vous puissiez continuer à apporter les modifications souhaitées. Je l’utilise parce que j’ai un site MVC modulaire qui est vendu aux entresockets clientes et qui doivent pouvoir déposer des DLL dans le dossier bin pour append de nouveaux modules. Je leur permets de changer le “HomeArea” dans la configuration AppSettings.

 var route = routes.MapRoute( "Home_Default", "", new {controller = "Home", action = "index" }, new[] { "IPC.Web.Core.Controllers" } ); route.DataTokens["area"] = area; 

Edit: Vous pouvez également essayer ceci dans votre AreaRegistration.RegisterArea pour la zone que vous souhaitez que l’utilisateur utilise par défaut. Je ne l’ai pas testé, mais AreaRegistrationContext.MapRoute ne définit pas route.DataTokens["area"] = this.AreaName; pour toi.

 context.MapRoute( "Home_Default", "", new {controller = "Home", action = "index" }, new[] { "IPC.Web.Core.Controllers" } ); 

on a déjà répondu à cela – c’est la syntaxe courte (ASP.net 3, 4, 5):

 routes.MapRoute("redirect all other requests", "{*url}", new { controller = "UnderConstruction", action = "Index" }).DataTokens = new RouteValueDictionary(new { area = "Shop" }); 

Merci à Aaron d’avoir souligné qu’il s’agit de localiser les points de vue, je l’ai mal compris.

[UPDATE] Je viens de créer un projet qui envoie l’utilisateur à une zone par défaut sans avoir à modifier le code ou les chemins de recherche:

Dans global.asax, inscrivez-vous comme d’habitude:

  public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = ""} // Parameter defaults, ); } 

dans Application_Start() , assurez-vous d’utiliser l’ordre suivant;

  protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); } 

dans votre zone d’enregistrement, utilisez

  public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( "ShopArea_default", "{controller}/{action}/{id}", new { action = "Index", id = "", controller = "MyRoute" }, new { controller = "MyRoute" } ); } 

Un exemple peut être trouvé à http://www.emphess.net/2010/01/31/areas-routes-and-defaults-in-mvc-2-rc/

J’espère vraiment que c’est ce que vous demandiez …

////

Je ne pense pas que l’écriture d’un pseudo ViewEngine soit la meilleure solution dans ce cas. (Manque de réputation, je ne peux pas commenter). WebFormsViewEngine est sensible à la zone et contient AreaViewLocationFormats qui est défini par défaut comme

 AreaViewLocationFormats = new[] { "~/Areas/{2}/Views/{1}/{0}.aspx", "~/Areas/{2}/Views/{1}/{0}.ascx", "~/Areas/{2}/Views/Shared/{0}.aspx", "~/Areas/{2}/Views/Shared/{0}.ascx", }; 

Je crois que vous n’adhérez pas à cette convention. Vous avez posté

 public ActionResult ActionY() { return View("~/Areas/AreaZ/views/ActionY.aspx"); } 

comme un hack de travail, mais cela devrait être

  return View("~/Areas/AreaZ/views/ControllerX/ActionY.aspx"); 

Si vous ne souhaitez pas suivre la convention, vous pouvez choisir un chemin court en vous basant sur WebFormViewEngine (par exemple dans MvcConsortingb) où vous pouvez définir les chemins de recherche dans le constructeur, ou – un peu de piratage en spécifiant votre convention comme ceci sur Application_Start :

 ((VirtualPathProviderViewEngine)ViewEngines.Engines[0]).AreaViewLocationFormats = ...; 

Cela devrait être fait avec un peu plus de soin, bien sûr, mais je pense que cela montre l’idée. Ces champs sont public dans VirtualPathProviderViewEngine dans MVC 2 RC.

Je suppose que vous voulez que l’utilisateur soit redirigé vers l’URL ~/AreaZ une fois qu’il a visité ~/ URL. J’obtiendrais au moyen du code suivant dans votre racine HomeController .

 public class HomeController { public ActionResult Index() { return RedirectToAction("ActionY", "ControllerX", new { Area = "AreaZ" }); } } 

Et la route suivante dans Global.asax .

 routes.MapRoute( "Redirection to AreaZ", Ssortingng.Empty, new { controller = "Home ", action = "Index" } ); 

Tout d’abord, quelle version de MVC2 utilisez-vous? Il y a eu des changements importants de preview2 à RC.

En supposant que vous utilisez le RC, je pense que le mappage des routes devrait avoir un aspect différent. Dans le AreaRegistration.cs dans votre région, vous pouvez enregistrer une sorte de route par défaut, par exemple

  context.MapRoute( "ShopArea_default", "{controller}/{action}/{id}", new { action = "Index", id = "", controller="MyRoute" } ); 

Le code ci-dessus enverra l’utilisateur au MyRouteController de notre ShopArea par défaut.

L’utilisation d’une chaîne vide en tant que second paramètre devrait générer une exception, car un contrôleur doit être spécifié.

Bien sûr, vous devrez changer la route par défaut dans Global.asax pour qu’elle n’interfère pas avec cette route par défaut, par exemple en utilisant un préfixe pour le site principal.

Voir aussi cette discussion et la réponse de Haack: MVC 2 AreaRegistration Routes Order

J’espère que cela t’aides.

L’ajout de ce qui suit à mon Application_Start fonctionne pour moi, même si je ne suis pas sûr que vous ayez ce paramètre dans RC:

 var engine = (WebFormViewEngine)ViewEngines.Engines.First(); // These additions allow me to route default requests for "/" to the home area engine.ViewLocationFormats = new ssortingng[] { "~/Views/{1}/{0}.aspx", "~/Views/{1}/{0}.ascx", "~/Areas/{1}/Views/{1}/{0}.aspx", // new "~/Areas/{1}/Views/{1}/{0}.ascx", // new "~/Areas/{1}/Views/{0}.aspx", // new "~/Areas/{1}/Views/{0}.ascx", // new "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.aspx", "~/Views/Shared/{0}.ascx" }; 

Ce que j’ai fait pour que cela fonctionne est le suivant:

  1. J’ai créé un contrôleur par défaut dans le dossier root / Controllers. J’ai nommé mon contrôleur DefaultController.
  2. Dans le contrôleur, j’ai ajouté le code suivant:

     namespace MyNameSpace.Controllers { public class DefaultController : Controller { // GET: Default public ActionResult Index() { return RedirectToAction("Index", "ControllerName", new {area = "FolderName"}); } } } 
  3. Dans mon RouterConfig.cs j’ai ajouté ce qui suit:

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

L’astuce derrière tout cela est que j’ai créé un constructeur par défaut qui sera toujours le contrôleur de démarrage à chaque démarrage de mon application. Lorsqu’il accède à ce contrôleur par défaut, il redirige vers tout contrôleur spécifié dans l’action d’index par défaut. Qui dans mon cas est

http://www.myurl.com/FolderName/ControllerName

.

 routes.MapRoute( "Area", "{area}/", new { area = "AreaZ", controller = "ControlerX ", action = "ActionY " } ); 

Avez-vous essayé ça?

La localisation des différents blocs de construction est effectuée dans le cycle de vie de la demande. L’une des premières étapes du cycle de vie de la requête ASP.NET MVC consiste à mapper l’URL demandée sur la méthode d’action correcte du contrôleur. Ce processus est appelé routage. Une route par défaut est initialisée dans le fichier Global.asax et décrit dans le framework ASP.NET MVC comment gérer une requête. Double-cliquer sur le fichier Global.asax dans le projet MvcApplication1 affichera le code suivant:

 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace MvcApplication1 { public class GlobalApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } } } 

Dans le gestionnaire d’événements Application_Start (), qui est déclenché chaque fois que l’application est compilée ou que le serveur Web est redémarré, une table de routage est enregistrée. La route par défaut est nommée Default et répond à une URL sous la forme http://www.example.com/ {controller} / {action} / {id}. Les variables entre {et} sont renseignées avec les valeurs réelles de l’URL de la demande ou avec les valeurs par défaut si aucune substitution n’est présente dans l’URL. Cette route par défaut sera mappée au contrôleur Home et à la méthode d’action Index, en fonction des parameters de routage par défaut. Nous n’aurons aucune autre action avec cette carte de routage.

Par défaut, toutes les URL possibles peuvent être mappées via cette route par défaut. Il est également possible de créer nos propres itinéraires. Par exemple, associons l’URL http://www.example.com/Employee/Maarten au contrôleur Employee, à l’action Show et au paramètre firstname. L’extrait de code suivant peut être inséré dans le fichier Global.asax que nous venons d’ouvrir. Étant donné que l’infrastructure ASP.NET MVC utilise la première route correspondante, cet extrait de code doit être inséré au-dessus de la route par défaut. sinon, l’itinéraire ne sera jamais utilisé.

 routes.MapRoute( "EmployeeShow", // Route name "Employee/{firstname}", // URL with parameters new { // Parameter defaults controller = "Employee", action = "Show", firstname = "" } ); 

Maintenant, ajoutons les composants nécessaires pour cette route. Tout d’abord, créez une classe nommée EmployeeController dans le dossier Contrôleurs. Vous pouvez le faire en ajoutant un nouvel élément au projet et en sélectionnant le modèle MVC Controller Class situé sous le Web | Catégorie MVC Supprimez la méthode d’action Index et remplacez-la par une méthode ou une action nommée Show. Cette méthode accepte un paramètre firstname et transmet les données au dictionnaire ViewData. Ce dictionnaire sera utilisé par la vue pour afficher les données.

La classe EmployeeController transmettra un object Employee à la vue. Cette classe Employé doit être ajoutée dans le dossier Modèles (cliquez avec le bouton droit sur ce dossier, puis sélectionnez Ajouter | Classe dans le menu contextuel). Voici le code de la classe Employee:

 namespace MvcApplication1.Models { public class Employee { public ssortingng FirstName { get; set; } public ssortingng LastName { get; set; } public ssortingng Email { get; set; } } } 

Bien que créer un moteur de vue personnalisé puisse fonctionner pour cela, vous pouvez toujours avoir une alternative:

  • Décidez ce que vous devez montrer par défaut.
  • Que quelque chose a un contrôleur et une action (et Area), non?
  • Ouvrez cet enregistrement de zone et ajoutez quelque chose comme ceci:
 public override void RegisterArea(AreaRegistrationContext context) { //this makes it work for the empty url (just domain) to act as current Area. context.MapRoute( "Area_empty", "", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, namespaces: new ssortingng[] { "Area controller namespace" } ); //other routes of the area } 

À votre santé!

La solution acceptée à cette question est, bien que résumant correctement la manière de créer un moteur de vue personnalisé, de ne pas répondre correctement à la question. Le problème est que Pino spécifie de manière incorrecte sa route par défaut . En particulier, sa définition “zone” est incorrecte. “Area” est vérifié via la collection DataTokens et doit être ajouté en tant que tel:

 var defaultRoute = new Route("",new RouteValueDictionary(){{"controller","Default"},{"action","Index"}},null/*constraints*/,new RouteValueDictionary(){{"area","Admin"}},new MvcRouteHandler()); defaultRoute.DataTokens.Add("Namespaces","MyProject.Web.Admin.Controller"); routes.Add(defaultRoute); 

La “zone” spécifiée dans l’object par défaut sera ignorée . Le code ci-dessus crée une route par défaut, qui attrape les requêtes sur la racine de votre site, puis appelle le contrôleur par défaut, l’action d’index dans la zone d’administration. Veuillez également noter que la clé “Namespaces” a été ajoutée à DataTokens, ceci est requirejs uniquement si vous avez plusieurs contrôleurs avec le même nom. Cette solution est vérifiée avec Mvc2 et Mvc3 .NET 3.5 / 4.0

Hum, je ne sais pas pourquoi toute cette programmation, je pense que le problème original est résolu facilement en spécifiant cette route par défaut …

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