none
Utilizar vistas en diferentes directorios para el mismo controlador RRS feed

  • Pregunta

  • Hola, estoy realizando un proyecto web en ASP.Net MVC.
    En un principio, todo bien, todo estupendo. En un punto determinado del proyecto me he puesto a realizar vistas específicas para la visualización móvil, todo funcionaría de modo espléndido si simplemente incorporase vistas con un sufijo "movil" por ejemplo como acciones y crease la acción determinada en el controlador.
    No obstante, no quiero cambiar ni los VM ni necesito modificar como se tratan las acciones del controlador, sólo quiero cambiar las vistas (que no sólo el formato, para eso sólo cambiaría el css, quiero/necesito cambiar las vistas cuando se conecte a través de un movil).
    Actualmente, tengo las rutas sin tocar, y según he podido comprobar ASP busca las vistas en el directorio del controlador y el shared, ahora bien, yo quiero que esas vistas concretas las busque como ahora, pero poniendo un "Mobile/" antes, es decir, si ahora cuando se accede a:
    http://nombreaplicacion/Controlador/Accion. Me utiliza el controlador ControladorController y la vista para dicha acción Views/Controlador/Accion.aspx
    Yo quiero que cuando se acceda a :
    http://nombreaplicacion/Mobile/Controlador/Accion. Me utilice el controlador ControladorController y la vista Views/Mobile/Controlador/Accion.aspx
    Es esto posible? He estado jugueteando con el maproute y no parece encontrarse ahi la solución, es decir, si puedo añadir un formato de url tal que así:
    Mobile/{controller}/{action} Que me utiliza el controlador y el método de acción correctamente, pero ASP sigue buscando las vistas en Views/Controlador/Accion.
    Como puedo hacer que ASP me busque la vista en Views/Mobile/Controlador/Accion cuando la url tenga el formato Mobile/{controller}/{accion} ?
    Es esto posible? Muchas gracias desde ya.
    jueves, 1 de diciembre de 2011 12:16

Respuestas

  • Buenas!

    Sí, si que es posible! :)

    La solución pasa por definirte tu propio ViewEngine que vaya a buscar las vistas donde tu necesites.

    Te muestro una posible implementación sacada del blog de Scott Hanselman (no la uses, no es correcta porque hay algún error relacionado con caching) pero que quiero enseñarte para que veas cual sería la idea:

    public class MobileRazorViewEngine : RazorViewEngine
    {
        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
     {
         ViewEngineResult result = null;
          if (request.Browser.IsMobileDevice)
          {
            // Añadimos Mobile/ a la ruta de las vistas si es un dispositivo móvil
             result = base.FindView(controllerContext, "Mobile/" + viewName, masterName, useCache);        
           }
           // Si no se encuentra la vista o bien no era mobil, hacemos lo mismo que antes:
          if (result == null || result.View == null) 
          {
                result = base.FindView(controllerContext, viewName, masterName, useCache);        
           }
         return result;
     }
    }
    

    Luego tan solo debes registrar este motor de vista en ASP.NET MVC:

    ViewEngines.Engines.Add(new MobileRazorViewEngine());
    

    Listo, con esto ya puedes tener tus vistas en Views/Controller/Mobile/XXXX  (p.ej. Views/Home/Mobile/Index.cshtml).

     Ok, como te he dicho, esta implementación tiene un error (derivado de como MVC3 realiza el caching de páginas) que hace que realmente no sea todo tan simple. Lo bueno del caso es que esto ya está implementado: http://www.hanselman.com/blog/NuGetPackageOfTheWeek10NewMobileViewEnginesForASPNETMVC3SpeccompatibleWithASPNETMVC4.aspx

    Y por cierto... parece que eso vendrá de serie con MVC4!

    Saludos!


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis
    • Marcado como respuesta frikinside lunes, 13 de febrero de 2012 13:24
    jueves, 1 de diciembre de 2011 14:48
  • Buenas!

    El problema que da el código que te he puesto en MVC3 es por temas de caching... Pero échale un vistazo al post que re he enlazado, allí está todo el código que funciona bien.

    Creo que es ASP.NET MVC3, pero en MVC2 debería ser parecido (o casi igual) salvo que en lugar de RazorViewEngine usarás WebFormViewEngine que es el que se encarga de las vistas en formato .aspx.

    Saludos y suerte!!!! :)


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis
    • Marcado como respuesta frikinside lunes, 13 de febrero de 2012 13:24
    viernes, 2 de diciembre de 2011 7:30

Todas las respuestas

  • Buenas!

    Sí, si que es posible! :)

    La solución pasa por definirte tu propio ViewEngine que vaya a buscar las vistas donde tu necesites.

    Te muestro una posible implementación sacada del blog de Scott Hanselman (no la uses, no es correcta porque hay algún error relacionado con caching) pero que quiero enseñarte para que veas cual sería la idea:

    public class MobileRazorViewEngine : RazorViewEngine
    {
        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
     {
         ViewEngineResult result = null;
          if (request.Browser.IsMobileDevice)
          {
            // Añadimos Mobile/ a la ruta de las vistas si es un dispositivo móvil
             result = base.FindView(controllerContext, "Mobile/" + viewName, masterName, useCache);        
           }
           // Si no se encuentra la vista o bien no era mobil, hacemos lo mismo que antes:
          if (result == null || result.View == null) 
          {
                result = base.FindView(controllerContext, viewName, masterName, useCache);        
           }
         return result;
     }
    }
    

    Luego tan solo debes registrar este motor de vista en ASP.NET MVC:

    ViewEngines.Engines.Add(new MobileRazorViewEngine());
    

    Listo, con esto ya puedes tener tus vistas en Views/Controller/Mobile/XXXX  (p.ej. Views/Home/Mobile/Index.cshtml).

     Ok, como te he dicho, esta implementación tiene un error (derivado de como MVC3 realiza el caching de páginas) que hace que realmente no sea todo tan simple. Lo bueno del caso es que esto ya está implementado: http://www.hanselman.com/blog/NuGetPackageOfTheWeek10NewMobileViewEnginesForASPNETMVC3SpeccompatibleWithASPNETMVC4.aspx

    Y por cierto... parece que eso vendrá de serie con MVC4!

    Saludos!


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis
    • Marcado como respuesta frikinside lunes, 13 de febrero de 2012 13:24
    jueves, 1 de diciembre de 2011 14:48
  • Buenas tardes,

    Lo primero de todo, muchas gracias por su respuesta!

    Actualmente estoy usando MVC2, por si es una información relevante (que podría ser perfectamente), por lo que no sé si dicho problema con el MVC3 me atañe o peor aun, es menos "salvable".

    Quizás soy yo que me lío un poco, y para terminar de aclarar el asunto, las vistas que quiero estarían en Views/Mobile/Controller/Action y no en Views/Controller/Mobile/Action. 

    Me imaginé (tal y como me lo has confirmado con tu respuesta) que era un problema con el motor de vistas, por lo que hice unas pruebas a modo de apaño en el global.asax, sólo para comprobar si la idea era viable.

    protected void Application_Start()
            {
                log4net.Config.XmlConfigurator.Configure();
    
                RutasMobile();
                ViewEngines.Engines.Add(new AreaViewEngine());
                
    
                ModelBinders.Binders.DefaultBinder = new SharpModelBinder();
    
                InitializeServiceLocator();
    
                AreaRegistration.RegisterAllAreas();
                RouteRegistrar.RegisterRoutesTo(RouteTable.Routes);
            }
    
            private void RutasMobile()
            {
                WebFormViewEngine motor= ViewEngines.Engines[0] as WebFormViewEngine;
                motor.ViewLocationFormats =
                   new string[] { 
                        "~/Views/Mobile/{1}/{0}.aspx", 
                        "~/Views/Mobile/{1}/{0}.ascx", 
              };
                motor.PartialViewLocationFormats = motor.ViewLocationFormats;
            }
    


    Con una modificación en las rutas como la siguiente:

            public static void RegisterRoutesTo(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });
    
                routes.MapRoute(
                    "Mobile",                                              // Route name
                    "Mobile/{controller}/{action}/{id}",                           // URL with parameters
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional }  // Parameter defaults
                );  
    
                routes.MapRoute(
                    "Default",                                              // Route name
                    "{controller}/{action}/{id}",                           // URL with parameters
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional }  // Parameter defaults
                );
            }
    


    Los resultados fueron bastante satisfactorios para las pruebas, ya que primero me buscaba en Mobile/Controlador/Accion gracias al nuevo "mapeo" de localizaciones y si lo encontraba, pues perfecto! Me lo mostraba. Y gracias al añadido en el mapa de rutas, al escribir Mobile/Controlador/Accion en la url, definía correctamente que el controller era Controlador y no Mobile.

     

    No obstante, eso no tiene futuro, ya que en el supuesto de que la carpeta Mobile ya contuviese todas vistas de la aplicación, siempre las encontraría primero con lo que serían esas vistas las únicas que se mostrarían, por lo que como prueba y viabilidad de la idea estaba muy bien, pero como solución era bastante coja.

    Por ello intente mejorar el apaño para ver si se podía solucionar esa eventualidad y si conseguía que eso funcionase, sólo sería mejorar la solución para que dejase de ser un apaño. Para ello modifiqué el global.asax que muestro a continuación:

     

    protected void Application_Start()
            {
                log4net.Config.XmlConfigurator.Configure();
    
                RutasMobile();
                ViewEngines.Engines.Add(new AreaViewEngine());
                
    
                ModelBinders.Binders.DefaultBinder = new SharpModelBinder();
    
                InitializeServiceLocator();
    
                AreaRegistration.RegisterAllAreas();
                RouteRegistrar.RegisterRoutesTo(RouteTable.Routes);
            }
    
            private void RutasMobile()
            {
                WebFormViewEngine motor= ViewEngines.Engines[0] as WebFormViewEngine;
                motor.ViewLocationFormats =
                   new string[] { 
                        "~/Views/{1}/{0}.aspx", 
                        "~/Views/{1}/{0}.ascx", 
                        "~/Views/Shared/{0}.aspx", 
                        "~/Views/Shared/{0}.ascx",
                        "~/Views/{2}/{1}/{0}.aspx", 
                        "~/Views/{2}/{1}/{0}.ascx", 
              };
                motor.PartialViewLocationFormats = motor.ViewLocationFormats;
            }
    

    Añadiendo ahora, las vistas predeterminadas primero, y una nueva variable de la ruta, para que no tenga otra opción si existe dicha cadena en la ruta.


    Unido a una modificación en las rutas:

    public static void RegisterRoutesTo(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });
    
                routes.MapRoute(
                    "Mobile",                                              // Route name
                    "{carpeta}/{controller}/{action}/{id}",                           // URL with parameters
                    new { carpeta = "Mobile", controller = "Home", action = "Index", id = UrlParameter.Optional }  // Parameter defaults
                );  
    
                routes.MapRoute(
                    "Default",                                              // Route name
                    "{controller}/{action}/{id}",                           // URL with parameters
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional }  // Parameter defaults
                );
            }
    


    Los resultados han sido bastante horribles e impredecibles, imagino que a pesar de haber estado un buen rato mirando ejemplos y documentaciones al respecto haya metido bastante la patuca. Supongo que el error reside o en el {2} del motor de vistas o en el {carpeta}, o dicho de otro modo, el {2} no se corresponde con {carpeta}. Y en caso de que ese no sea el error, entonces estoy bastante más perdido de lo que pensaba >.<

     

    La solución que me planteas, estimado eduard, me parece excelente sin duda, y tendría que probarlo, imagino que sería cuestión de quitar "Razor" ya que si no me equivoco estoy usando el ViewEngine y no el RazorViewEngine. Y... bueno, no se me había ocurrido utilizar el IsMobileDevice ya que había leido críticas sobre su verdadera funcionalidad, yo usaba en su lugar una verificación en la vista predeterminada que me llevaba a donde yo quería una primera vez y luego los enlaces se encargarían del resto.

    <%
        string user_agent = Request.ServerVariables["HTTP_USER_AGENT"];
        Regex navegador = new Regex(@"android.+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino", RegexOptions.IgnoreCase | RegexOptions.Multiline);
        Regex version = new Regex(@"1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|e\\-|e\\/|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\\-|2|g)|yas\\-|your|zeto|zte\\-", RegexOptions.IgnoreCase | RegexOptions.Multiline);
        if ((navegador.IsMatch(user_agent) || version.IsMatch(user_agent.Substring(0, 4))))
        {
            string url = "http://" + Request.Url.Host;
            if (Request.Url.Port != 0)
            {
                 url+= ":" + Request.Url.Port;
            }
            url += "/Mobile/Login";
            Response.Redirect(url);
        }
    %>
    


    No obstante, me parece mucho más elegante y sencillo, para mi caso concreto imagino que habría que modificar la solución que me propones de una manera muy sencilla, cambiando esto:

    // Añadimos Mobile/ a la ruta de las vistas si es un dispositivo móvil
             result = base.FindView(controllerContext, "Mobile/" + viewName, masterName, useCache); 
    

    por esto:

    // Añadimos Mobile/ a la ruta de las vistas si es un dispositivo móvil
             result = base.FindView("Mobile/" +controllerContext,  viewName, masterName, useCache); 
    


    Aunque, si daba problemas con el MVC3 quizás antes deba comprobar si esto es posible en MVC2.

     

    De todos modos, la idea me agrada, y ahora ya tengo una confirmación mejor de por donde van los tiros para poder llegar a una solución a mi problema, muchas gracias por todo y a ver si podemos llegar a una solución final ;)

     

    jueves, 1 de diciembre de 2011 16:34
  • Buenas!

    El problema que da el código que te he puesto en MVC3 es por temas de caching... Pero échale un vistazo al post que re he enlazado, allí está todo el código que funciona bien.

    Creo que es ASP.NET MVC3, pero en MVC2 debería ser parecido (o casi igual) salvo que en lugar de RazorViewEngine usarás WebFormViewEngine que es el que se encarga de las vistas en formato .aspx.

    Saludos y suerte!!!! :)


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis
    • Marcado como respuesta frikinside lunes, 13 de febrero de 2012 13:24
    viernes, 2 de diciembre de 2011 7:30
  • Muy buenas!

    Por cierto, que despistado soy, me sirvió en extremo la asistencia que me proporcionastes, por si a alguien le sirve, ésto es lo que hice:

    Cree una clase en donde defino unos métodos státicos que me dicen si un navegador es Mobile y otros métodos para cambiar el enrutamiento.

    public class RoutesViewsMobile
        {
            public RoutesViewsMobile() { }
    
            public static bool esMovil(string userAgent, bool browserMobile)
            {
                string user_agent = userAgent;
                Regex navegador = new Regex(@"android.+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino", RegexOptions.IgnoreCase | RegexOptions.Multiline);
                Regex version = new Regex(@"1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|e\\-|e\\/|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\\-|2|g)|yas\\-|your|zeto|zte\\-", RegexOptions.IgnoreCase | RegexOptions.Multiline);
    
                return (browserMobile || (navegador.IsMatch(user_agent) || version.IsMatch(user_agent.Substring(0, 4))));
            }
    
            //Cambio de motor de búsqueda de vistas y del enrutamiento
            public static void RutasMobile()
            {
    
                //Nuevo mapa de rutas
                RouteTable.Routes.Clear();
                RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                RouteTable.Routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });
                RouteTable.Routes.MapRoute(
                    "Mobile",                                              // Route name
                    "Mobile/{controller}/{action}/{id}",                   // URL with parameters
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional }  // Parameter defaults
                );
                RouteTable.Routes.MapRoute(
                    "Default",                                              // Route name
                    "{controller}/{action}/{id}",                   // URL with parameters
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional }  // Parameter defaults
                );
            }
            //Cambio de motor de búsqueda de vistas y del enrutamiento
            public static void RutasNoMobile()
            {
                //Nuevo mapa de rutas
                RouteTable.Routes.Clear();
                RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                RouteTable.Routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });
                RouteTable.Routes.MapRoute(
                    "Default",                                              // Route name
                    "{controller}/{action}/{id}",                   // URL with parameters
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional }  // Parameter defaults
                );
            }
        }

    Y una clase para sobreescribir los métodos de búsqueda del ViewEngine

    namespace Microsoft.Web.Mvc
    {
        public class MobileViewEngine : WebFormViewEngine
        {
            
            public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName,
                                                      string masterName, bool useCache)
            {
                bool mobile = RoutesViewsMobile.esMovil(controllerContext.HttpContext.Request.ServerVariables["HTTP_USER_AGENT"], controllerContext.HttpContext.Request.Browser.IsMobileDevice);
                //Cambiamos el enrutamiento si es mobile
                if (mobile && RouteTable.Routes.Count == 3)
                    RoutesViewsMobile.RutasMobile();
                else if (!mobile && RouteTable.Routes.Count == 4)
                    RoutesViewsMobile.RutasNoMobile();
                ViewEngineResult result = NewFindView(controllerContext, viewName, masterName, useCache,mobile);
    
                // Si no encontramos la vista mobile, que me busque una normal
                if (mobile && (result == null || result.View == null))
                    result = NewFindView(controllerContext, viewName, masterName, useCache,false);
                return result;
            }
    
            private ViewEngineResult NewFindView(ControllerContext controllerContext, string viewName, string masterName,
                                                 bool useCache,bool mobile)
            {
                // Sacamos el controlador de la ruta
                string controller = controllerContext.RouteData.Values["controller"].ToString();
                string area = "";
                try
                {
                    area = controllerContext.RouteData.DataTokens["area"].ToString();
                }
                catch
                {
                }
    
                controller = mobile ? Path.Combine("Mobile", controller) : controller;
                // Creamos la llave cada vez, para evitar los problemas de caching   
    
                    string keyPath = Path.Combine(area, Path.Combine(controller, viewName));
                // Probamos la caché por los problemas de caching           
                if (useCache)
                {
                    //Miramos si la localización ha sido cacheada.               
                    string cacheLocation = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, keyPath);
                    if (!string.IsNullOrEmpty(cacheLocation))
                        return new ViewEngineResult(CreateView(controllerContext, cacheLocation, masterName), this);
                }
    
                // Guardamos los intentos de acceso para gestionar los errores
                var attempts = new List<string>();
    
                string[] locationFormats = string.IsNullOrEmpty(area) ? ViewLocationFormats : AreaViewLocationFormats;
    
                // Revisamos todos los roots paths y rellenamos sus datos. Luego comprobamos y cacheamos           
                foreach (string rootPath in locationFormats)
                {
                    string currentPath = string.IsNullOrEmpty(area)
                                             ? string.Format(rootPath, viewName, controller)
                                             : string.Format(rootPath, viewName, controller, area);
    
                    if (FileExists(controllerContext, currentPath))
                    {
                        ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, keyPath, currentPath);
    
                        return new ViewEngineResult(CreateView(controllerContext, currentPath, masterName), this);
                    }
    
                    // Si no lo encontramos, lo añadimos a la lista de intentos.               
                    attempts.Add(currentPath);
                }
    
                // Si no lo hemos encontrado, mostramos los intentos. Para propósitos de depuración           
                return new ViewEngineResult(attempts.Distinct().ToList());
            }
        }
    }</string>

    Ésta es la solución que encontré gracias a la inestimable ayuda de eduard tomás para una aplicación MVC2.

    Espero que sirva de ayuda también para futuras consultas al respecto



    • Editado frikinside lunes, 13 de febrero de 2012 15:28
    lunes, 13 de febrero de 2012 15:26