tag route pagina net mvc establecer data crear asp all asp.net-mvc asp.net-mvc-2

asp.net-mvc - route - establecer pagina principal mvc



Cómo establecer una ruta predeterminada(a un área) en MVC (13)

Agregar lo siguiente a mi Application_Start funciona para mí, aunque no estoy seguro de si tiene esta configuración en 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" };

Ok esto se ha preguntado antes, pero no hay una solución sólida por ahí. Entonces, para mi propio propósito y el de otros que puedan encontrarlo útil.

En MVC2 (ASP.NET) lo quiero para que cuando alguien navegue al sitio web, haya un área predeterminada especificada. Así que navegar a mi sitio debería enviarte a ControllerX ActionY en AreaZ.

Usando la siguiente ruta en Global.asax

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

Ahora esto funciona, ya que intenta servir la página correcta. Sin embargo, MVC procede a buscar la Vista en la raíz del sitio y no en la carpeta Área.

¿Hay una manera de resolver esto?

EDITAR

Hay una ''Solución'' y eso es en ControllerX, ActionY devuelve la ruta completa de la vista. Algo así como un truco, pero funciona. Sin embargo, espero que haya una mejor solución.

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

Editar:

Esto también se convierte en un problema al tener un enlace de acción HTML de la página. Si el área no está configurada, Action Link se muestra en blanco.

¿Es todo esto por diseño o un defecto?


Así es como lo hice. No sé por qué MapRoute () no le permite establecer el área, pero devuelve el objeto de ruta para que pueda continuar haciendo los cambios adicionales que desee. Utilizo esto porque tengo un sitio MVC modular que se vende a clientes empresariales y necesitan poder colocar dlls en la carpeta bin para agregar nuevos módulos. Les permito cambiar la "HomeArea" en la configuración de AppSettings.

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

Editar: puede probar esto también en su ÁreaRegistro.RegistrarArea para el área que desea que el usuario vaya de forma predeterminada. No lo he probado, pero AreaRegistrationContext.MapRoute establece route.DataTokens["area"] = this.AreaName; para ti.

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


Bueno, aunque la creación de un motor de vista personalizada puede funcionar para esto, aún puede tener una alternativa:

  • Decide lo que necesitas mostrar de forma predeterminada.
  • Ese algo tiene controlador y acción (y Área), ¿verdad?
  • Abra el registro de Área y agregue algo como esto:

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 }

¡Aclamaciones!


Este me interesó, y finalmente tuve la oportunidad de investigarlo. Aparentemente, otras personas no han entendido que este es un problema para encontrar la vista , no es un problema con el enrutamiento en sí mismo, y eso es probablemente porque el título de su pregunta indica que se trata de enrutar.

En cualquier caso, como se trata de un problema relacionado con la Vista, la única forma de obtener lo que desea es anular el motor de vista predeterminado . Normalmente, cuando haces esto, es con el simple propósito de cambiar tu motor de visualización (es decir, a Spark, NHaml, etc.). En este caso, no es la lógica de creación de vista que debemos sobrescribir, sino los métodos FindPartialView y FindView en la clase VirtualPathProviderViewEngine .

Puedes agradecer a tus estrellas de la suerte que estos métodos son de hecho virtuales, porque ni siquiera se puede acceder a todo lo demás en VirtualPathProviderViewEngine es privado, y eso hace que sea muy molesto anular la lógica de búsqueda porque básicamente tienes que reescribir la mitad del código que es Ya se ha escrito si desea que funcione bien con la caché de ubicación y los formatos de ubicación. Después de excavar en Reflector finalmente logré encontrar una solución funcional.

Lo que he hecho aquí es crear primero un AbstractAwareViewEngine que se deriva directamente de VirtualPathProviderViewEngine lugar de WebFormViewEngine . Hice esto para que, si quieres crear vistas de Spark (o lo que sea), aún puedas usar esta clase como tipo de base.

El código siguiente es bastante largo, para darle un resumen rápido de lo que realmente hace: le permite poner un {2} en el formato de ubicación, que corresponde al nombre del área, de la misma manera que {1} corresponde a el nombre del controlador. ¡Eso es! Para eso tenemos que escribir todo este código:

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<string>(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; } }

Ahora, como se dijo, este no es un motor concreto, por lo que debe crearlo también. Esta parte, afortunadamente, es mucho más fácil, todo lo que tenemos que hacer es establecer los formatos predeterminados y realmente crear las vistas:

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

Tenga en cuenta que hemos agregado algunas entradas a los ViewLocationFormats estándar. Estas son las nuevas {2} entradas, donde el {2} se asignará al area colocamos en el RouteData . He dejado los MasterLocationFormats solo, pero obviamente puedes cambiar eso si quieres.

Ahora modifica tu global.asax para registrar este motor de vista:

Global.asax.cs

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

... y registrar la ruta predeterminada:

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

Ahora AreaController el AreaController nos AreaController :

DefaultController.cs (en ~ / Controladores /)

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

Obviamente, necesitamos la estructura del directorio y la vista para ir con eso; lo mantendremos muy sencillo:

TestView.aspx (en ~ / Areas / AreaZ / Views / Default / or ~ / Areas / AreaZ / Views / Shared /)

<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %> <h2>TestView</h2> This is a test view in AreaZ.

Y eso es. Finalmente, hemos terminado .

En su mayor parte, debería poder tomar BaseAreaAwareViewEngine y AreaAwareViewEngine y soltarlo en cualquier proyecto de MVC, por lo tanto, aunque haya sido necesario un gran número de código para hacerlo, solo tiene que escribirlo una vez. Después de eso, solo es cuestión de editar unas pocas líneas en global.asax.cs y crear la estructura de su sitio.


Gracias a Aaron por señalar que se trata de ubicar las vistas, lo entendí mal.

[ACTUALIZAR] Acabo de crear un proyecto que envía al usuario a un Área por defecto sin jugar con ninguno de los códigos o rutas de búsqueda:

En global.asax, regístrese como de costumbre:

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

en Application_Start() , asegúrese de usar el siguiente orden;

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

en su área de registro, use

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

Un ejemplo se puede encontrar en http://www.emphess.net/2010/01/31/areas-routes-and-defaults-in-mvc-2-rc/

Realmente espero que esto sea lo que estabas pidiendo ...

////

No creo que escribir un pseudo ViewEngine sea ​​la mejor solución en este caso. (A falta de reputación, no puedo comentar). El WebFormsViewEngine es consciente de la zona y contiene los AreaViewLocationFormats que se definen por defecto como

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

Creo que no se adhiere a esta convención. Publicaste

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

como un truco de trabajo, pero eso debería ser

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

Sin embargo, si no quiere seguir la convención, puede tomar una ruta corta derivando de WebFormViewEngine (que se hace en MvcContrib, por ejemplo) donde puede establecer las rutas de búsqueda en el constructor, o - un poco hacky- al especificar su convención de esta manera en Application_Start :

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

Esto debería realizarse con un poco más de cuidado, por supuesto, pero creo que muestra la idea. Estos campos son public en VirtualPathProviderViewEngine en MVC 2 RC.


La solución aceptada para esta pregunta es, aunque es correcto al resumir cómo crear un motor de vista personalizado, no responde la pregunta correctamente. El problema aquí es que Pino está especificando incorrectamente su ruta predeterminada . Particularmente, su definición de "área" es incorrecta. El "área" se verifica a través de la colección DataTokens y se debe agregar como tal:

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

El "área" especificada en el objeto predeterminado se ignorará . El código anterior crea una ruta predeterminada, que capta las solicitudes en la raíz de su sitio y luego llama al controlador predeterminado, acción de índice en el área de administración. Tenga en cuenta también que se agrega la clave "Espacios de nombres" a DataTokens, esto solo es necesario si tiene múltiples controladores con el mismo nombre. Esta solución se verifica con Mvc2 y Mvc3 .NET 3.5 / 4.0


La ubicación de los diferentes bloques de construcción se realiza en el ciclo de vida de la solicitud. Uno de los primeros pasos en el ciclo de vida de la solicitud ASP.NET MVC es mapear la URL solicitada al método de acción del controlador correcto. Este proceso se conoce como enrutamiento. Una ruta predeterminada se inicializa en el archivo Global.asax y describe el marco ASP.NET MVC cómo manejar una solicitud. Al hacer doble clic en el archivo Global.asax en el proyecto MvcApplication1 se mostrará el siguiente código:

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

En el controlador de eventos Application_Start (), que se activa cada vez que se compila la aplicación o se reinicia el servidor web, se registra una tabla de rutas. La ruta predeterminada se denomina Predeterminada y responde a una URL en forma de http://www.example.com/ {controlador} / {acción} / {id}. Las variables entre {y} se rellenan con los valores reales de la URL de solicitud o con los valores predeterminados si no hay anulación en la URL. Esta ruta predeterminada se asignará al controlador de inicio y al método de acción de índice, de acuerdo con los parámetros de enrutamiento predeterminados. No tendremos ninguna otra acción con este mapa de enrutamiento.

De forma predeterminada, todas las URL posibles se pueden asignar a través de esta ruta predeterminada. También es posible crear nuestras propias rutas. Por ejemplo, asignemos el URL http://www.example.com/Employee/Maarten al controlador del empleado, la acción Mostrar y el parámetro nombre. El siguiente fragmento de código se puede insertar en el archivo Global.asax que acabamos de abrir. Debido a que el marco MVC de ASP.NET utiliza la primera ruta coincidente, este fragmento de código debe insertarse por encima de la ruta predeterminada; de lo contrario, la ruta nunca será utilizada.

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

Ahora, agreguemos los componentes necesarios para esta ruta. Antes que nada, crea una clase llamada EmployeeController en la carpeta Controladores. Puede hacer esto agregando un nuevo elemento al proyecto y seleccionando la plantilla MVC Controller Class ubicada debajo de la Web | Categoría MVC Elimine el método de acción Índice y reemplácelo con un método o acción llamada Mostrar. Este método acepta un parámetro firstname y pasa los datos al diccionario ViewData. Este diccionario será utilizado por la vista para mostrar datos.

La clase EmployeeController pasará un objeto Employee a la vista. Esta clase Employee debe agregarse en la carpeta Models (haga clic derecho en esta carpeta y luego seleccione Add | Class en el menú contextual). Aquí está el código para la clase Empleado:

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


Lo que hice para que esto funcione es lo siguiente:

  1. Creé un controlador predeterminado en la carpeta raíz / Controladores. Llamé a mi controlador DefaultController.
  2. En el controlador agregué el siguiente código:

    namespace MyNameSpace.Controllers { public class DefaultController : Controller { // GET: Default public ActionResult Index() { return RedirectToAction("Index", "ControllerName", new {area = "FolderName"}); } } }

  3. En mi RouterConfig.cs agregué lo siguiente:

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

El truco detrás de todo esto es que hice un constructor predeterminado que siempre será el controlador de inicio cada vez que se inicie mi aplicación. Cuando llegue a ese controlador predeterminado, se redireccionará a cualquier controlador que especifique en la acción de índice predeterminada. Que en mi caso es

www.myurl.com/FolderName/ControllerName

.


Primero, ¿qué versión de MVC2 estás usando? Se han producido cambios significativos desde la vista previa2 a RC.

Suponiendo que use el RC, creo que el mapeo de ruta debe verse de manera diferente. En AreaRegistration.cs en su área, puede registrar algún tipo de ruta predeterminada, por ejemplo

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

El código anterior enviará al usuario a MyRouteController en nuestra ShopArea por defecto.

Usar una cadena vacía como segundo parámetro debería generar una excepción, porque se debe especificar un controlador.

Por supuesto, tendrá que cambiar la ruta predeterminada en Global.asax para que no interfiera con esta ruta predeterminada, por ejemplo, usando un prefijo para el sitio principal.

También vea este hilo y la respuesta de Haack: MVC 2 AreaRegistration Routes Order

Espero que esto ayude.


Supongo que quiere que el usuario sea redirigido a ~/AreaZ URL una vez que haya visitado ~/ URL. Lo lograría mediante el siguiente código dentro de tu HomeController raíz.

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

Y la siguiente ruta en Global.asax .

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


incluso ya se respondió: esta es la sintaxis corta (ASP.net 3, 4, 5):

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


ummm, no sé por qué toda esta programación, creo que el problema original se resuelve fácilmente al especificar esta ruta predeterminada ...

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


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

¿Has probado eso?