Hola a todos, hace mucho que no me daba el tiempo de escribir un artículo, sin embargo, ahora que estoy revisando asp.net en más profundidad para mi próximo examen de certificación, voy a compartirles las cosas interesantes que encuentre por ahí.

Ok, let's go

Así como en el examen, voy a empezar comentándoles el problema y el escenario del mismo.
Es común que en las aplicaciones que serán usadas por muchos usuarios se sometan a pruebas de diseño, ya que es necesario evaluar que alternativa de diseño genera el mejor ratio de conversión.
Por otro lado, es también muy deseable muchas veces que una aplicación pueda cambiar su aspecto visual sin la necesidad de cambiar el código, tal vez desde un panel de administración.

¿Cómo hacemos eso con ASP.net MVC?

El framework de ASP.net MVC contiene un sinnúmero de puntos de extensibilidad, dado que todo el framework ha sido construido de manera modular, podemos reemplazar o extender la funcionalidad de cualquiera de sus componentes para cumplir nuestros requerimientos.
En este caso solo es necesario extender nuestro motor de vista (viewEngine).

A continuación, pueden ver la interfaz IViewEngine, que es la que implementa nuestro motor de vistas.

Enfoquémonos en los dos primeros métodos, que son los responsables de encontrar las vistas y es justo lo que queremos sobrescribir.
**Les sorprenderá saber que es necesario una mínima cantidad de código para generar cambios muy interesantes. **

En nuestro caso necesitamos saber cómo funciona el motor de vistas de Razor, el RazorViewEngine, ya que es el que necesitamos extender. Este motor de vistas utiliza un listado de ubicaciones donde buscar por vistas cada vez que se llama al método View() desde nuestro controlador. Las ubicaciones, que para muchos son muy conocidas son las siguientes:

Ubicación Parámetros
~/Views/{1}/{0}.cshtml
~/Views/Shared/{0}.cshtml

~/Areas/{2}/Views/{1}/{0}.cshtml
~/Areas/{2}/Views/Shared/{0}.cshtml
0 - Acción
1 - Controlador
2 - Área

Ahora bien, lo único que nosotros haremos será extender estas ubicaciones y soportar temas. Para que las ubicaciones a buscar queden así:

Ubicación Parámetros
~/Views/Themes/{tema}/{1}/{0}.cshtml
~/Views/Themes/{tema}/Shared/{0}.cshtml

~/Areas/Themes/{tema}/{2}/Views/{1}/{0}.cshtml
~/Areas/Themes/{tema}/{2}/Views/Shared/{0}.cshtml
0 - Acción
1 - Controlador
2 - Área
tema - Nombre del tema

Ok veamos todo esto en acción

Esta es mi solución básica, que como verán contiene las carpetas por defecto. Podemos decir que es una aplicación trivial de mvc.

La cual se ve la siguiente manera.

Lo primero que haremos, por cuestiones de orden será crear un folder llamado Infraestructura.
Dentro de este folder agregaremos una clase a la que llamaremos ThemeViewEngine.

Haremos que esta clase herede de RazorViewEngine, cuya clase está ubicada en el espacio de nombres System.Web.Mvc.
Y agregaremos las nuevas ubicaciones para las vistas considerando ahora el nombre del tema, tal como se muestra en el siguiente fragmento de código.

Ahora que hemos construido nuestro motor de vista solo necesitamos suplirle el parámetro tema y registrarlo globalmente.
Vamos a nuestro archivo Global.asax y agregamos algunas líneas de código que leen el parámetro tema del web.config y si existe un valor lo usa para registrar nuestro motor de vistas en la ubicación 0, es decir nuestro motor de vistas se encuentra primero. Si el motor de vista no encuentra la vista utilizara el motor de vistas por defecto.

**Esto último es importante debido a que permite que el tema sobrescriba parcial o completamente las vistas de la aplicación. **

Ahora que tenemos registrado nuestro motor de vistas necesitamos configurarlo en el web.config y agregar algunos temas :D

Tengo dos temas que agregare a mi proyecto, como pueden ver he agregado unas vistas en las respectivas carpetas.

Por último, el web.config es muy sencillo de configurar solo agregamos el nombre del tema como un AppSetting.

Y ahora que tenemos todo listo, veámoslo en acción ;)

Y eso sería todo espero les haya gustado :D

Cualquier duda pueden dejar su comentario debajo o escribirme a @jesulink2514 en twitter.