Come impostare un percorso predefinito (in un’area) in MVC

Ok, questo è stato chiesto prima, ma non esiste una soluzione solida. Quindi per lo scopo di me stesso e di altri che potrebbero trovare utile questo.

In MVC2 (ASP.NET) lo voglio così quando qualcuno naviga sul sito web, viene specificata un’area predefinita. Quindi la navigazione verso il mio sito dovrebbe inviarti a ControllerX ActionY in AreaZ.

Utilizzando il seguente percorso nel Global.asax

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

Ora questo funziona come in esso tenta di servire la pagina corretta. Tuttavia, MVC procede alla ricerca della vista nella radice del sito e non nella cartella Area.

C’è un modo per risolvere questo?

MODIFICARE

Esiste una “Soluzione” e in ControllerX, AzioneY restituisce il percorso completo della vista. Un po ‘di mod, ma funziona. Comunque spero che ci sia una soluzione migliore.

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

Modificare:

Questo diventa anche un problema quando si ha un LinkLink HTML della pagina. Se l’area non è impostata, il link di azione viene visualizzato in bianco.

Tutto questo è di progettazione o un difetto?

Questo mi interessava e finalmente ho avuto la possibilità di esaminarlo. Altre persone apparentemente non hanno capito che questo è un problema con la ricerca della vista , non un problema con il routing stesso – ed è probabilmente perché il titolo della tua domanda indica che si tratta di routing.

In ogni caso, poiché si tratta di un problema relativo alla visualizzazione, l’unico modo per ottenere ciò che si desidera è sovrascrivere il motore di visualizzazione predefinito . Normalmente, quando lo fai, è per il semplice scopo di cambiare il tuo motore di visualizzazione (cioè Spark, NHaml, ecc.). In questo caso, non è la logica di creazione della vista che dobbiamo sovrascrivere, ma i metodi FindPartialView e FindView nella class VirtualPathProviderViewEngine .

Puoi ringraziare le tue stelle fortunate che questi metodi sono di fatto virtuali, perché tutto il resto in VirtualPathProviderViewEngine non è nemmeno accessibile – è privato, e questo rende molto fastidioso scavalcare la logica di ricerca perché devi sostanzialmente riscrivere metà del codice che è è già stato scritto se si desidera che funzioni con la cache di posizione e i formati di posizione. Dopo alcuni scavi in ​​Reflector sono finalmente riuscito a trovare una soluzione funzionante.

Quello che ho fatto qui è di creare prima un AreaAwareViewEngine astratto che deriva direttamente da VirtualPathProviderViewEngine invece di WebFormViewEngine . Ho fatto questo in modo che se vuoi creare viste Spark (o qualsiasi altra cosa), puoi comunque usare questa class come tipo base.

Il codice sotto è piuttosto prolisso, quindi per darti un breve riassunto di ciò che effettivamente fa: ti permette di mettere un {2} nel formato della posizione, che corrisponde al nome dell’area, allo stesso modo in cui {1} corrisponde a il nome del controller. Questo è tutto! Questo è quello che dovevamo scrivere tutto questo codice per:

BaseAreaAwareViewEngine.cs

 public abstract class BaseAreaAwareViewEngine : VirtualPathProviderViewEngine { private static readonly string[] EmptyLocations = { }; public override ViewEngineResult FindView( ControllerContext controllerContext, string viewName, string masterName, bool useCache) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (string.IsNullOrEmpty(viewName)) { throw new ArgumentNullException(viewName, "Value cannot be null or empty."); } string area = getArea(controllerContext); return FindAreaView(controllerContext, area, viewName, masterName, useCache); } public override ViewEngineResult FindPartialView( ControllerContext controllerContext, string partialViewName, bool useCache) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (string.IsNullOrEmpty(partialViewName)) { throw new ArgumentNullException(partialViewName, "Value cannot be null or empty."); } string area = getArea(controllerContext); return FindAreaPartialView(controllerContext, area, partialViewName, useCache); } protected virtual ViewEngineResult FindAreaView( ControllerContext controllerContext, string areaName, string viewName, string masterName, bool useCache) { string controllerName = controllerContext.RouteData.GetRequiredString("controller"); string[] searchedViewPaths; string viewPath = GetPath(controllerContext, ViewLocationFormats, "ViewLocationFormats", viewName, controllerName, areaName, "View", useCache, out searchedViewPaths); string[] searchedMasterPaths; string masterPath = GetPath(controllerContext, MasterLocationFormats, "MasterLocationFormats", masterName, controllerName, areaName, "Master", useCache, out searchedMasterPaths); if (!string.IsNullOrEmpty(viewPath) && (!string.IsNullOrEmpty(masterPath) || string.IsNullOrEmpty(masterName))) { return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this); } return new ViewEngineResult( searchedViewPaths.Union(searchedMasterPaths)); } protected virtual ViewEngineResult FindAreaPartialView( ControllerContext controllerContext, string areaName, string viewName, bool useCache) { string controllerName = controllerContext.RouteData.GetRequiredString("controller"); string[] searchedViewPaths; string partialViewPath = GetPath(controllerContext, ViewLocationFormats, "PartialViewLocationFormats", viewName, controllerName, areaName, "Partial", useCache, out searchedViewPaths); if (!string.IsNullOrEmpty(partialViewPath)) { return new ViewEngineResult(CreatePartialView(controllerContext, partialViewPath), this); } return new ViewEngineResult(searchedViewPaths); } protected string CreateCacheKey(string prefix, string name, string controller, string area) { return string.Format(CultureInfo.InvariantCulture, ":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}:", base.GetType().AssemblyQualifiedName, prefix, name, controller, area); } protected string GetPath(ControllerContext controllerContext, string[] locations, string locationsPropertyName, string name, string controllerName, string areaName, string cacheKeyPrefix, bool useCache, out string[] searchedLocations) { searchedLocations = EmptyLocations; if (string.IsNullOrEmpty(name)) { return string.Empty; } if ((locations == null) || (locations.Length == 0)) { throw new InvalidOperationException(string.Format("The property " + "'{0}' cannot be null or empty.", locationsPropertyName)); } bool isSpecificPath = IsSpecificPath(name); string key = CreateCacheKey(cacheKeyPrefix, name, isSpecificPath ? string.Empty : controllerName, isSpecificPath ? string.Empty : areaName); if (useCache) { string 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 string GetPathFromGeneralName(ControllerContext controllerContext, string[] locations, string name, string controllerName, string areaName, string cacheKey, ref string[] searchedLocations) { string virtualPath = string.Empty; searchedLocations = new string[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; } } 

Ora come detto, questo non è un motore concreto, quindi devi crearlo anche tu. Questa parte, fortunatamente, è molto più semplice, tutto ciò che dobbiamo fare è impostare i formati predefiniti e creare effettivamente le viste:

AreaAwareViewEngine.cs

 public class AreaAwareViewEngine : BaseAreaAwareViewEngine { public AreaAwareViewEngine() { MasterLocationFormats = new string[] { "~/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 string[] { "~/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, string 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, string viewPath, string masterPath) { if (viewPath.EndsWith(".cshtml")) return new RazorView(controllerContext, viewPath, masterPath, false, null); else return new WebFormView(controllerContext, viewPath, masterPath); } } 

Si noti che abbiamo aggiunto alcune voci ai ViewLocationFormats standard. Queste sono le nuove {2} voci, dove il {2} sarà mappato area abbiamo inserito in RouteData . Ho lasciato solo MasterLocationFormats , ma ovviamente puoi cambiarlo se vuoi.

Ora modifica il tuo global.asax per registrare questo motore di visualizzazione:

Global.asax.cs

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

... e registra la rotta predefinita:

 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 = "" } ); } 

Ora Crea l' AreaController abbiamo appena fatto riferimento:

DefaultController.cs (in ~ / Controllers /)

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

Ovviamente abbiamo bisogno della struttura delle directory e vista per seguirlo - terremo questo semplicissimo:

TestView.aspx (in ~ / Aree / AreaZ / Viste / Predefinito / o ~ / Aree / AreaZ / Viste / Condiviso /)

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

TestView

This is a test view in AreaZ.

E questo è tutto. Finalmente, abbiamo finito .

Per la maggior parte, dovresti essere in grado di prendere solo il BaseAreaAwareViewEngine e AreaAwareViewEngine e rilasciarlo in qualsiasi progetto MVC, quindi anche se ci vuole un sacco di codice per fare questo, devi solo scriverlo una volta. Dopodiché, è solo questione di modificare alcune righe in global.asax.cs e creare la struttura del tuo sito.

Questo è come l’ho fatto. Non so perché MapRoute () non ti permette di impostare l’area, ma restituisce l’object del percorso in modo che tu possa continuare ad apportare eventuali modifiche aggiuntive. Lo uso perché ho un sito MVC modulare che viene venduto ai clienti aziendali e devono essere in grado di rilasciare le DLL nella cartella bin per aggiungere nuovi moduli. Consentono loro di cambiare “HomeArea” nella configurazione di AppSettings.

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

Modifica: puoi provare anche questo nella tua AreaRegistration.RegisterArea per l’area che vuoi che l’utente utilizzi per impostazione predefinita. Non l’ho testato ma AreaRegistrationContext.MapRoute imposta route.DataTokens["area"] = this.AreaName; per te.

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

anche se è già stato risposto – questa è la syntax breve (ASP.net 3, 4, 5):

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

Grazie ad Aaron per aver sottolineato che si tratta di individuare le opinioni, ho frainteso quello.

[AGGIORNAMENTO] Ho appena creato un progetto che invia l’utente a un’area per impostazione predefinita senza creare problemi con il codice o i percorsi di ricerca:

In global.asax, registrati come al solito:

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

in Application_Start() , assicurati di utilizzare il seguente ordine;

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

nella tua area di registrazione, usa

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

Un esempio può essere trovato su http://www.emphess.net/2010/01/31/areas-routes-and-defaults-in-mvc-2-rc/

Spero davvero che questo sia quello che stavi chiedendo …

////

Non penso che scrivere una pseudo ViewEngine sia la soluzione migliore in questo caso. (Mancanza di reputazione, non posso commentare). Il WebFormsViewEngine è Area aware e contiene AreaViewLocationFormats che è definito per default come

 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", }; 

Credo che tu non aderisca a questa convenzione. Hai postato

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

come un trucco da lavoro, ma dovrebbe essere così

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

Se non si desidera seguire la convenzione, tuttavia, è ansible intraprendere un breve percorso derivando da WebFormViewEngine (ad esempio in MvcContrib) in cui è ansible impostare i percorsi di ricerca nel costruttore, oppure – un po ‘hacky, specificando la tua convenzione come su Application_Start :

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

Questo dovrebbe essere eseguito con un po ‘più di attenzione, ovviamente, ma penso che mostri l’idea. Questi campi sono public in VirtualPathProviderViewEngine in MVC 2 RC.

Immagino tu voglia che l’utente sia reindirizzato a ~/AreaZ URL una volta che ha visitato ~/ URL. Mi piacerebbe ottenere tramite il seguente codice all’interno del tuo HomeController root.

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

E il seguente percorso in Global.asax .

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

Innanzitutto, quale versione di MVC2 stai usando? Ci sono stati cambiamenti significativi da preview2 a RC.

Supponendo che tu usi la RC, penso che la mapping del percorso dovrebbe avere un aspetto diverso. In AreaRegistration.cs nella tua zona, puoi registrare un qualche tipo di percorso predefinito, ad es

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

Il codice sopra invierà l’utente al MyRouteController nel nostro ShopArea per impostazione predefinita.

L’utilizzo di una stringa vuota come secondo parametro dovrebbe generare un’eccezione, in quanto è necessario specificare un controller.

Ovviamente dovrai modificare la rotta predefinita in Global.asax modo che non interferisca con questa rotta predefinita, ad esempio utilizzando un prefisso per il sito principale.

Vedi anche questo thread e la risposta di Haack: MVC 2 AreaRegistration Routes Order

Spero che questo ti aiuti.

Aggiungendo il seguente al mio Application_Start funziona per me, anche se non sono sicuro che tu abbia questa impostazione in RC:

 var engine = (WebFormViewEngine)ViewEngines.Engines.First(); // These additions allow me to route default requests for "/" to the home area engine.ViewLocationFormats = new string[] { "~/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" }; 

Quello che ho fatto per farlo funzionare è il seguente:

  1. Ho creato un controller predefinito nella cartella root / controller. Ho chiamato il mio controller DefaultController.
  2. Nel controller ho aggiunto il seguente codice:

     namespace MyNameSpace.Controllers { public class DefaultController : Controller { // GET: Default public ActionResult Index() { return RedirectToAction("Index", "ControllerName", new {area = "FolderName"}); } } } 
  3. Nel mio RouterConfig.cs ho aggiunto quanto segue:

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

Il trucco dietro tutto questo è che ho creato un costruttore predefinito che sarà sempre il controller di avvio ogni volta che viene avviata la mia app. Quando raggiunge il controller predefinito, reindirizza a qualsiasi controller specificato nell’azione indice predefinita. Che nel mio caso è

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

.

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

Hai provato?

La localizzazione dei diversi blocchi costitutivi avviene nel ciclo di vita della richiesta. Uno dei primi passaggi nel ciclo di vita della richiesta MVC ASP.NET sta mappando l’URL richiesto al metodo di azione del controller corretto. Questo processo è indicato come routing. Una route predefinita viene inizializzata nel file Global.asax e descrive il framework ASP.NET MVC come gestire una richiesta. Facendo doppio clic sul file Global.asax nel progetto MvcApplication1 verrà visualizzato il seguente codice:

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

Nel gestore di eventi Application_Start (), che viene generato ogni volta che l’applicazione viene compilata o il server Web viene riavviato, viene registrata una tabella di route. La route predefinita è denominata Default e risponde a un URL nel formato di http://www.example.com/ {controller} / {action} / {id}. Le variabili tra {e} vengono popolate con valori effettivi dall’URL della richiesta o con i valori predefiniti se non è presente alcuna sovrascrittura nell’URL. Questa rotta predefinita verrà mappata al controller Home e al metodo di azione Indice, in base ai parametri di routing predefiniti. Non avremo altre azioni con questa mappa di routing.

Per impostazione predefinita, tutti i possibili URL possono essere mappati attraverso questa rotta predefinita. È anche ansible creare i nostri percorsi. Ad esempio, mappiamo l’URL http://www.example.com/Employee/Maarten al controller Employee, all’azione Show e al parametro firstname. Il seguente frammento di codice può essere inserito nel file Global.asax che abbiamo appena aperto. Poiché il framework ASP.NET MVC utilizza la prima route corrispondente, questo snippet di codice deve essere inserito sopra la route predefinita; altrimenti il ​​percorso non verrà mai utilizzato.

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

Ora, aggiungiamo i componenti necessari per questa rotta. Prima di tutto, creare una class denominata EmployeeController nella cartella Controller. È ansible farlo aggiungendo un nuovo elemento al progetto e selezionando il modello MVC Controller Class situato sotto il Web | Categoria MVC. Rimuovere il metodo di azione Indice e sostituirlo con un metodo o un’azione denominata Mostra. Questo metodo accetta un parametro firstname e passa i dati nel dizionario ViewData. Questo dizionario verrà utilizzato dalla vista per visualizzare i dati.

La class EmployeeController passerà un object Employee alla vista. Questa class Employee deve essere aggiunta nella cartella Models (fare clic con il tasto destro su questa cartella e selezionare Aggiungi | Class dal menu di scelta rapida). Ecco il codice per la class Employee:

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

Bene, mentre la creazione di un motore di visualizzazione personalizzato può funzionare per questo, puoi comunque avere un’alternativa:

  • Decidi cosa devi mostrare per impostazione predefinita.
  • Quel qualcosa ha controller e azione (e Area), giusto?
  • Apri la registrazione dell’Area e aggiungi qualcosa di simile a questo:
 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 string[] { "Area controller namespace" } ); //other routes of the area } 

Saluti!

La soluzione accettata per questa domanda è, sebbene corretta nel riassumere come creare un motore di visualizzazione personalizzato, non risponde correttamente alla domanda. Il problema è che Pino sta specificando erroneamente la sua rotta predefinita . In particolare la sua definizione di “area” non è corretta. “Area” viene controllato tramite la raccolta DataTokens e deve essere aggiunto come tale:

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

L’area specificata “area” in default verrà ignorata . Il codice sopra crea un percorso predefinito, che attira le richieste verso la root del tuo sito e chiama Call controller predefinito, azione Index in Admin area. Si noti inoltre che la chiave “Namespaces” è stata aggiunta a DataTokens, questa operazione è necessaria solo se si hanno più controller con lo stesso nome. Questa soluzione è stata verificata con Mvc2 e Mvc3 .NET 3.5 / 4.0

ummm, non so perché tutta questa programmazione, penso che il problema originale sia risolto facilmente specificando questa rotta predefinita …

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