DisplayModes en MVC 4

Como venimos comentando desde la aparición de la preview de MVC 4, el Display Mode o modo de visualización es un nuevo mecanismo que permite la creación de aplicaciones capaces de retornar vistas específicas según las características y capacidades del cliente conectado u otros parámetros del entorno de la petición.

Esto tiene mucha utilidad directa, por ejemplo, a la hora de construir aplicaciones web que adapten su interfaz en función de si el cliente es un dispositivo móvil o desktop, pero como casi siembre ocurre en el framework, se trata de un mecanismo muy extensible y fácil de adaptar a otras necesidades.

¿Cómo funciona?

Las aplicaciones, tanto ASP.NET MVC 4 como WebPages 2, disponen de una lista de display modes admitidos, a la que se puede acceder a través de la propiedad DisplayModeProvider.Instance.Modes. Esta colección está poblada inicialmente por dos elementos, aunque podemos añadir todos los que nos interesen siempre que éstos implementen el interfaz IDisplayMode, cuya definición es la siguiente:

public interface IDisplayMode
{
    string DisplayModeId { get; } 
    bool CanHandleContext(HttpContextBase httpContext);

    DisplayInfo GetDisplayInfo(HttpContextBase httpContext, 
                               string virtualPath,
                               Func<string, bool> virtualPathExists);
}

Cuando llega una petición, el mismo sistema de routing recorrerá la colección DisplayModeProvider.Instance.Modes, e invocará el método CanHandleContext() de cada uno de los objetos IDisplayMode encontrados en ella. El primero que responda afirmativamente será introducido en el contexto de la petición como modo de visualización activo.

A partir de ese momento es posible consultar el display mode actual a través de la propiedad DisplayMode disponible en la clase ControllerContext .

Continuando con el ciclo de vida de la petición, una vez ésta ha sido procesada por el controlador, si éste retorna una vista entrarán en juego los motores de vistas o view engines. Éstos son los encargados, entre otras cosas, de localizar el archivo de plantilla (.cshtml, aspx, etc.) a usar para renderizar la vista en función del nombre de ésta, del nombre del controlador, y, si procede, del área activa. Por ejemplo, si es necesario retornar una vista llamada “index”, del controlador “customers”, en el área “admin”, el motor de vistas Razor (implementado en la clase RazorViewEngine) será capaz de localizar y crear la vista a partir de la plantilla disponible en /areas/admin/views/customers/index.cshtml.

Pues bien, el modo de visualización activo toma relevancia justo en el momento de la localización de la plantilla. El view engine encargado de procesar la vista llamará al método GetDisplayInfo() de éste, desde donde tendrá la oportunidad de modificar la ruta hacia el archivo. En la implementación por defecto, el identificador del display mode activo, tomado de su propiedad DisplayModeId, será insertado como prefijo de la extensión del archivo, de forma, por ejemplo, que la vista que tradicionalmente hubiéramos encontrado en “~/views/home/index.cshtml”, usando el modo de visualización identificado como “mobile” se encontraría en “~/views/home/index.mobile.cshtml”.

Display Modes por defecto

Antes había comentado que al arrancar una aplicación MVC 4 o WebPages 2, la colección de modos de visualización, DisplayModeProvider.Instance.Modes, es cargada con dos elementos. Ambos son del tipo DefaultDisplayMode, clase que, por supuesto, implementa IDisplayMode, e implementa unas bases bastante genéricas y reutilizables.

El primer display mode que encontramos es el específico para dispositivos móviles, que nivel a de framework se define más o menos así:

var displayMode = new DefaultDisplayMode(DisplayModeProvider.MobileDisplayModeId)
                        {
                            ContextCondition =
                                context => context.GetOverriddenBrowser().IsMobileDevice
                        };

El parámetro que estamos enviando al constructor es el identificador que daremos al modo de visualización (y, por tanto, que será usado como prefijo de la extensión del archivo de la vista). La constante DisplayModeProvider.MobileDisplayModeId está definida con un valor de “Mobile” en el código, y por esta razón las vistas específicas para móviles las encontraremos en archivos del tipo “xyz.mobile.cshtml”.

Por otra parte, haciendo uso de la inicialización rápida de objetos de C#, establecemos en la propiedad ContextCondition la condición que activará el display mode, expresado como lambda. La expresión lambda recibe un parámetro de tipo HttpContextBase y debe retornar un booleano, que será el valor que retorne el método CanHandleContext(), como recordaréis, invocado por el framework para averiguar si un IDisplayMode puede procesar una petición.

Por cierto, el GetOverridenBrowser() que veis ahí es otra característica nueva que encontraremos en MVC 4; de momento, quedaos con que, simplemente, nos devuelte información sobre el cliente que ha realizado la petición. Le dedicaremos un post en exclusiva más adelante ;-)

El segundo display mode que encontramos en DisplayModeProvider.Instance.Modes es una instancia de la clase DefaultDisplayMode a la que no se ha establecido ninguna propiedad; las llamadas a su método CanHandleContext() siempre retornan true, y su identificador es una cadena vacía.

Teniendo este objeto al final de la lista al más puro estilo catch-all, conseguimos que si ninguno de los display modes es capaz de gestionar adecuadamente la petición, se procesará éste, y dado que su identificador es una cadena de texto en blanco, no se producirá ningún cambio en el nombre del archivo. En otras palabras, el framework seguirá funcionando como hasta ahora, por lo que este elemento es, al fin y al cabo, el que garantiza la compatibilidad hacia atrás de este mecanismo.

Creación de display modes personalizados

Como ya podréis intuir, es bastante sencillo crear nuevos display modes, cuya activación dependa de las condiciones que más nos interesen. Lo más sencillo es utilizar como base el DefaultDisplayMode, por ejemplo así:

DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("iPhone")
{
    ContextCondition = (context => context.Request.UserAgent.IndexOf
        ("iPhone", StringComparison.OrdinalIgnoreCase) >= 0)
});

Con el código anterior estaríamos creando un nuevo display mode que se activaría cuando en el user-agent de la petición (enviado en el encabezado HTTP) se encuentre el texto “iPhone”, lo que permitiría crear vistas específicas para este dispositivo nombrándolas de la forma “xyz.iphone.cshtml”.

Otra posibilidad sería crear una clase que implemente IDisplayMode e introducir en ella la lógica que deseemos ejecutar en cada uno de los miembros definidos en el contrato. Pero el ejemplo y el escenario en el que podría ser utilizado lo dejamos para un futuro post ;-)


Publicado en: Variable not found.

Published 17/7/2012 17:02 por José M. Aguilar
Comparte este post:
http://geeks.ms/blogs/jmaguilar/archive/2012/07/17/displaymodes-en-mvc-4.aspx