Pregunta

Estoy trabajando mi camino a través de algunos ASP.NET MVC leyendo y tengo una aplicación web en el trabajo que voy a migrar de WebForms a MVC.Una de las peticiones de características que espero conseguir en el proceso es tener una visión simplificada que se devuelve si el usuario de un dispositivo móvil.

No acabo de ver dónde está el mejor lugar es para implementar ese tipo de lógica.Estoy seguro de que hay una mejor manera de añadir un if/else para el Navegador.IsMobileDevice en cada acción que devuelve una vista.¿Qué tipo de opciones tengo que hacer esto?

¿Fue útil?

Solución

Actualización:Esta solución tiene un error sutil.El marco de MVC llamada en FindView/FindPartialView dos veces:una vez con useCache=true, y si que no devuelve un resultado, una vez con useCache=false.Dado que sólo hay una caché para todos los tipos de puntos de vista, los usuarios móviles pueden acabar viendo las vistas del escritorio si un navegador de escritorio fue el primero en llegar.

Para aquellos interesados en el uso personalizado de vista de los motores para resolver este problema, Scott Hanselman ha actualizado su solución aquí:

http://www.hanselman.com/blog/ABetterASPNETMVCMobileDeviceCapabilitiesViewEngine.aspx

(Disculpas por la respuesta secuestrar, yo no quiero que nadie más tenga que pasar por esto!)

Editado por roufamatic (2010-11-17)


La primera cosa que quiero hacer es introducir el Dispositivo Móvil Del Navegador De Archivos para su proyecto.El uso de este archivo puede orientar lo que nunca dispositivo que desea, sin tener que conocer los detalles de lo que esos dispositivos pueden enviar sus encabezados.Este archivo ya ha hecho el trabajo por usted.A continuación, utilizar la Solicitud.Navegador de la propiedad a medida que la vista que desea devolver.

Segundo, una estrategia sobre cómo desea organizar sus puntos de vista en la carpeta Views.Yo prefiero dejar la versión de escritorio en la raíz y, a continuación, tener un Móvil de la carpeta.Por ejemplo, la Casa de la vista de carpeta tendría este aspecto:

  • Casa
    • Móvil
      • iPhone
        • Índice.aspx
      • BlackBerry
        • Índice.aspx
    • Índice.aspx

No estoy de acuerdo con @Mehrdad sobre el uso de una vista personalizada del motor.El motor de la vista sirve para más de un propósito y uno de esos efectos es encontrar puntos de vista para el controlador.Usted puede hacer esto por la invalidación de la FindView método.En este método, usted puede hacer sus comprobaciones sobre dónde encontrar la vista.Después de que usted sepa que el dispositivo está utilizando su sitio web, usted puede usar la estrategia que se le ocurrieron para la organización de sus puntos de vista para devolver la vista de ese dispositivo.

public class CustomViewEngine : WebFormViewEngine
{
    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        // Logic for finding views in your project using your strategy for organizing your views under the Views folder.
        ViewEngineResult result = null;
        var request = controllerContext.HttpContext.Request;

        // iPhone Detection
        if (request.UserAgent.IndexOf("iPhone",
   StringComparison.OrdinalIgnoreCase) > 0)
        {
            result = base.FindView(controllerContext, "Mobile/iPhone/" + viewName, masterName, useCache);
        }

        // Blackberry Detection
        if (request.UserAgent.IndexOf("BlackBerry",
   StringComparison.OrdinalIgnoreCase) > 0)
        {
            result = base.FindView(controllerContext, "Mobile/BlackBerry/" + viewName, masterName, useCache);
        }

        // Default Mobile
        if (request.Browser.IsMobileDevice)
        {
            result = base.FindView(controllerContext, "Mobile/" + viewName, masterName, useCache);
        }

        // Desktop
        if (result == null || result.View == null)
        {
            result = base.FindView(controllerContext, viewName, masterName, useCache);
        }

        return result;
    }
}

El código anterior permite establecer la vista, basándose en su estrategia.La caída es la vista del escritorio, si no se encontró el dispositivo o, si no hay un valor predeterminado vista móvil.

Si usted decide poner la lógica en su controlador en lugar de crear un motor de la vista.La mejor solución sería crear una personalizada ActionFilterAttribute que usted puede decorar su controlador con.A continuación, reemplazar el OnActionExecuted método para determinar el dispositivo que está viendo su sitio.Usted puede comprobar esto blog sobre cómo.El post también tiene algunos buenos enlaces a algunos de Mezcla de videos sobre este mismo tema.

Otros consejos

En el patrón Modelo-Vista-Controlador, es el controlador que selecciona la vista, por lo que, no es tan malo para añadir una declaración if y volver a una conclusión acertada. Puede encapsular la declaración if en un método y llamarlo:

return AdaptedView(Browser.IsMobileDevice, "MyView.aspx", model);

Como alternativa, puede crear un motor de vista que se ejecuta dinámicamente una vista en función de si es o no móvil. No soy un fan de este enfoque, ya que creo que el controlador debe estar a cargo. Por ejemplo, si usted está navegando en el iPhone, es posible que desee para ver la versión completa de escritorio en lugar. En el primer enfoque, que le pasa el indicador booleano apropiado, pero en el segundo, las cosas se vuelven más complicadas.

Creo que el lugar adecuado para conectar esta funcionalidad es costumbre ViewEngine. Sin embargo, usted debe ser consciente de cómo el método IViewEngine.FindView es llamado por el ViewEngineCollection (encontrará más información sobre este aquí ).

href="http://www.hanselman.com/blog/ABetterASPNETMVCMobileDeviceCapabilitiesViewEngine.aspx" rel="nofollow noreferrer"> solución sugerida por Scott Hanselman no funciona correctamente. Puede encontrar mi implementación de ejemplo de este enfoque aquí . Compruebe el archivo Léame que describe cómo se puede repetir un comportamiento incorrecto.

I sugieren otro enfoque que comprueba si una vista no se encontró por ViewEngine original y si el parámetro useCache es true, comprueba si vista existen en ViewEngine original con parámetro useCache=false.

Es demasiado complejo para poner todo el código aquí, pero usted puede encontrar el enfoque sugerido en práctica en mi patio de juegos de código abierto aquí . Compruebe clase MobileViewEngine y unidad de pruebas.

Algunas características MobileViewEngine:

  • funciona correctamente con vista almacenamiento en caché y caché de usos originales vista motor.
  • Soporta:. Nombres de vista tiro y ver los caminos relativos (~ / Vistas / index) utilizados por la plantilla MvcContrib T4
  • vista Resuelve "Índice" de la siguiente manera:
    • Mobile/Platform/Index -. Si existe la vista y una plataforma de dispositivos móviles (iPhone, Android, etc.) se alistó en la lista apoyada
    • Mobile/Index - vista para todos los demás dispositivos móviles. Si la vista no existe puede repliegue opcionalmente a la versión vista de escritorio.
    • Index - para la versión vista de escritorio.
  • Puede personalizar jerarquía de vistas móvil (por ejemplo Mobile/ Platform/Manufacturer) o personalizar vista móvil resolución ruta mediante la adición / cambio de las reglas de dispositivos (ver MobileDeviceRule y PlatformSpecificRule).

Hope, esto ayudará

Esta es una versión que funciona en realidad, ambos con T4MVC y en modo de lanzamiento (en el que se habilita el almacenamiento en caché de puntos de vista). Sin embargo, toma el cuidado de los controles de usuario y URL absolutas / relativas. Se requiere que el dispositivo móvil Explorador de archivos .

public class MobileCapableWebFormViewEngine : WebFormViewEngine
{

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        if (viewPath.EndsWith(".ascx"))
            masterPath = "";
        return base.CreateView(controllerContext, viewPath, masterPath);
    }
    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        useCache = false;
        ViewEngineResult result = null;
        var request = controllerContext.HttpContext.Request;

        if (request.Browser.IsMobileDevice || request["mobile"] != null || request.Url.Host.StartsWith("m."))
        {
            var mobileViewName = GetMobileViewName(viewName);

            result = base.FindView(controllerContext, mobileViewName, masterName, useCache);
            if (result == null || result.View == null)
            {
                result = base.FindView(controllerContext, viewName, "Mobile", useCache);
            }
        }

        if (result == null || result.View == null)
        {
            result = base.FindView(controllerContext, viewName, masterName, useCache);
        }

        return result;
    }

    private static string GetMobileViewName(string partialViewName)
    {
        var i = partialViewName.LastIndexOf('/');
        return i > 0
                   ? partialViewName.Remove(i) + "/Mobile" + partialViewName.Substring(i)
                   : "Mobile/" + partialViewName;
    }
}

Su lógica de la base debe ser el mismo en los controladores y sólo la vista que se tiene por qué va a cambiar lo que el controlador está en que el sí es necesario la declaración if / else para servir a la visión correcta para cada acción del controlador como ha afirmado.

Una alternativa sería que envuelva la lógica del controlador en un DLL separado y luego tener diferentes controladores / caminos para la versión móvil. Si un controlador regularmente recibe una solicitud desde un dispositivo móvil puede redirigir a su área móvil que contiene todos los controladores de móviles que utilizan la lógica del controlador compartido. Esta solución también le permitiría hacer '' retorcimientos que son específicos para los controladores móviles y no tener que afectan a sus controladores regulares.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top