ASP.NET MVC 3: Layouts y Secciones con Razor

Este es otro post de una serie que estoy haciendo sobre algunas características sobre ASP.NET MVC 3:

En este post vamos a entrar en más detalles sobre cómo funcionan el diseño de páginas con Razor. En concreto, vamos a ver cómo podemos tener varias secciones no continuas y reemplazables en un diseño - y habilitar a vistas basadas en diseños para que se rellenen opcionalmente con estas secciones en tiempo de ejecución. La sintaxis de razor para esto es limpia y concisa.

También os mostraré cómo podemos chequear dinámicamente si una sección de diseño ha sido definida, y cómo ofrecer contenido alternativo (o un diseño alternativo) en el caso de que esa sección no se haya especificado en la vista. Esto nos ofrece una forma fácil de personalizar la interfaz de usuario de nuestro sitio y lo hace limpio y DRY desde la perspectiva de la implementación.

¿Que es el diseño/layouts?

Normalmente querréis mantener un look&feel consistente sobre las páginas de vuestro sitio/aplicación web. ASP.NET 2.0 introdujo el concepto de "master pages" que nos permitían esto usando páginas .aspx. Razor también soporta este concepto y lo llama "layout" - que nos permite definir una plantilla común para un sitio, y heredar su look&feel por todas las vistas/páginas de nuestro sitio.

Hemos hablado sobre los conceptos básicos sobre los archivos de layout de Razor en el post ASP.NET MVC 3: Layouts con Razor. En el post de hoy vamos a entrar más profundamente a hablar sobre cómo podemos definir varias regiones, no contínuas y reemplazables en un archivo de layout que podemos rellenar opcionalmente en tiempo de ejecución.

Escenario de layout

Vamos a ver cómo podemos implementar un escenario simple de layout con ASP.NET MVC 3 y Razor. Vamos a implementar algunas interfaces de usuario en las que tendremos una cabecera común y un pié para todas nuestras páginas. TAmbién añadiremos una barra lateral a la derecha para el layout común de nuestro sitio.

En algunas páginas personalizaremos la barra lateral para que contenga contenido específico de la página en la que se incluye:

Y en otras páginas (que no tienen contenido específico para la barra lateral) lo rellenaremos con un contenido por defecto:

Usaremos ASP.NET MVC 3 y Razor para hacer que esta personalización sea sencilla.

Aquí tenéis un tutorial paso a paso sobre cómo crear el sitio anterior con ASP.NET MVC 3 y Razor.

Paso 1: Crear un nuevo proyecto con un layout para la sección "Body".

Empezaremos con el menú "File->New Project" de Visual Studio para crear un nuevo proyecto ASP.NET MVC 3. Crearemos el nuevo proyecto usando la plantilla "Empty":

Esto creará un nuevo proyecto sin controladores por defecto:

Creando el HomeController

Hacemos clic derecho en el directorio "Controller" y seleccionamos la opción "Add->Controller". Esto hará aparecer el diálogo "Add Controller":

Llamaremos al nuevo controlador "HomeController". Cuando hacemos clic en el botón "Add",  Visual Studio añdirá la clase HomeController al proyecto con un método de acción "Index" por defecto que devuelve una vista.

No necesitaremos escribir ninguna lógica de controlador para este ejemplo - así que lo dejaremos como está.

Creando una Vista.

El siguiente paso es implementar la vista asociada al método de acción Index de la clase HomeController. Para implementar esa vista, haremos clic derecho en el método "HomeController.Index()¨ y seleccionaremos el comando "Add View":

Esto nos mostrará el diálogo "Add View" de Visual Studio:

No tenemos que cambiar ninguna de las opciones que salen por defect (el nombre de la plantilla es calcula automáticamente porque hemos llamado al menú "AddView" desde el método Index).

Cuando hacemos clic en el botón "Add", se ha añadido una plantilla de vista de Razor "Index.cshtml" al directorio ViewsHome del proyecto. Añadamos algún contenido estático por defecto:

Fijáos que no tenemos ninguna sección de <html> o <body> definida en la plantilla. Esto es porque vamos a basarnos en una plantilla de layout para poner esos elementos y usarlos para definir el aspecto común y la estructura del sito (asegurándonos que es consistente en todas las páginas y URLs del sitio).

Personalizando nuestro archivo de Layout

Vamos a abrir y personalizar el archivo por defecto "_Layout.cshtml" que se añadió automáticamente al directorio ViewShared cuando creamos el proyecto:

El contenido por defecto (ver arriba) es muy básico y simplemente muestra el título (si se ha especificado en el controlador o en la plantilla de la vista) y añade enlaces a una hoja de estilos y a jQuery. La llamada a "RenderBody()" indica donde se muestra el contenido de nuestro archivo Index.cshtml cuando se envíe al navegador.

Vamos a modificar la plantilla de Layout para añadir una cabecera común, un pié y una barra lateral al sitio:

Ahora editaremos el archivo "Site.css" del directorio Content del proyecto para añadir 4 reglas de CSS:

Ahora cuando ejecutemos el proyecto y navegemos a la url homt "/" veremos la siguiente página:

Fijáos cómo el contenido de  HomeController de la plantilla de la vista y la plantilla de Layout se han mezclado para tener una respuesta HTML.

Aquí tenéis el HTML que se ha enviado desde el servidor:

Paso 2: Añadir la sección de la barra lateral

Por ahora nuestro sitio tiene una plantilla de layout con sólo una sección - lo que llamamos la sección de "body" de la respuesta.

Razor también soporta tener secciones nombradas en las plantillas de layout. Estas secciones se pueden definir en cualquier sitio del archivo de layout (incluso en la sección <head>) y nos permite devolver contenido dinámico en varias regioens, no continuas.

Definiendo la sección "SideBar" de nuestro Layout.

Vamos a actualizar la plantilla de Layout para definir una sección más "SideBar" de contenido que se renderizará en la región <div id="sidebar"> de nuestro HTML. Podemos hacer esto llamando al método de acción RenderSection(string sectionName, bool required)en el archivo Layout.cshtml:

El primer parámetro del método RenderSection() indica el nombre de la sección que queremos renderizar en esa posición de la plantilla de layout. El segundo parámetro es opcional, y nos permite definir que la sección que estamos renderizando es requerida o no. Si una sección es "requerida", Razor lanzará un error en tiempo de ejecución si esa sección no se ha implementado en una plantilla de vista que esté basada en el archivo de layout (lo que hace más fácil encontrar los errores). Si una sección no es requerida, entonces la presencia en la plantilla de vista es opcional, y el codigo RenderSection() no renderizará nada en tiempo de ejecución si no se ha definido.

Hemos hecho el cambio anterior al archivo de layout, vamos a refrescar el navegador y vamos a ver cómo se muestra ahora:

Fijáos que actualmente no tenemos contenidoen el div SideBar- esto es porque la plantilla de vista Index.cshtml no implementa la nueva sección "SideBar".

Implementando la sección SideBar en nuestra plantilla de vista

Vamos a cambiar la página home para que tenga una sección SideBar para que muestre algún contenido. Podemos hacer esto abriendo el archivo Index.cshtml, y añadiendo una sección "SideBar". Esto lo hacemos usando la sintaxis @section SectionName{}:

Podríamos poner la declaración de la sección SideBar en cualquier sitio de la plantilla de vista. Creo que es más claro definirlo al principio o al final del archivo - pero eso son solo gustos personales.

Podemos incluir cualqueir contenido o código que queramos en la declaración @section. Fijaos cómo estoy usando código C# para mostrar la hora actual en la parte de abajo de la sección. TAmbién podría haber escrito algún código quue accedan a un modelo de objetos fuertemente tipado pasandoselo a la plantilla Index.cshtml.

Fijaos que hemos hecho estos cambios, podemos refrescar el navegador otra vez y ver el contenido del SideBar - que hemos especificado en la página principal de nuestro sitio - ahora se incluye en el HTML que se envía al navegador:

La sección SideBar se ha mezclado con el HTML de respuesta:

Paso 3: Detectar si se ha implementado una sección de Layout

Razor nos ofrece la posibilidad de comprobar (desde un archivo de layout) si se ha definido una sección en una plantilla de vista, y nos permite ofrecer una salida alternativa si no se ha especificado la sección. Esto nos ofrece una forma muy conveniente de especificar un aspecto opcional en las secciones del layout.

Vamos amodificar el archivo de Layout para aprovechar esta capacidad. Vamos a comprobar si se ha definido la sección "sideBar" en la plantilla de vista a renderizar (usando el método IsSectionDefined()), y si es así renderizaremos la sección. Si no se ha definido la sección, vamos a renderizar un contenido por defecto:

Nota: Debéis aseguraros que las llamadas al método RenderSEction() van precedidas del caracter @ - que le dice a Razor que ejectue el HelperResult que devuelve y mezla en el contenido de la sección en el lugar adecuado. Fijáos cómo hemos escrito el@RenderSection("SideBar") en lugar de llamar sólo a RenderSEction("SideBar"). Si no, tendremos un error.

Simplemente estamos renderizando un string estático (<p>Default SideBar Content</p>) si no se define la sección. En un sitio del mundo real habría que refactorizar este contenido por defecto para que se guardase en una plantilla parcial (Que renderizaríamos usando el método Html.RenderPartial() en el bloque del else) o usar el método Html.Action() en el else para encapsular tanto la logica y el renderizado del sidebar por defecto.

Cuando refrescamos nuestra página principal, veremos el mimso contenido en el SideBar que en el ejemplo anterior. Esto es porque hemos implementado la sección SideBar en la plantilla de vista Index.cshtml (y de esta menra el layout lo ha renderizado).

Vamos a implementar la url "/Home/About" para nuesro sitio añadiendo el método de acción "About" en nuesro HomeController:

El método About simplemente renderiza una vista al cliente cuando se invoca. Podemos implementar su correspondiente plantilla de vista haciendo clic derecho en el método About(), usando el comando "Add View" para crear la plantilla de vista About.cshtml.

Implementaremos la plantilla de vista About.cshtml de la siguiente manera. Fijaos que no estamos definiendo una sección "SideBar":

Cuando navegamos a la url /Home/About veremos el contenido que hemos indicado arriba en la sección body, y el contenido por defecto de SideBar se renderizará:

El archivo de layout ha determinado en tiempo de ejecución que no hay una sección SideBar en About.cshtml, y ha renderizado el contenido por defecto.

Un último truco ...

Supongamos que más tarde decidimos que en lugar de renerizar el contenido por defecto de sidebar, queremos esconder el sidebar completamente en las páginas que no tengan una sección sidebar. Podemos implementar este cambio haciendo una pequeña modificación a nuestro layout de manera que el contenido del sidebar (y el HTMl que lo rodea) sólo se renderize si está definida la sección sideBar. El código para ello sería:

Razor es lo suficentemente flexible para que podamos hacer cambios como este sin tener que modificar ninguna de nuestras plantillas de vista (ni cambiar ninguna lógica del controlador) para conseguir esto. Haciendo este sencillo cambio a nuestro archivo de layout lo conseguimos. Este tipo de flexibilidad hace a Razor increiblemente podersoso y productivo.

Resumen

La capacidad del layout de Razor nos permite definir una plantilla común para el sitio, y heredar su look&feel por todas nuestras vistas/páginas.

Razor nos permite definir multiples secciones, no continuas en las plantillas de layout que pueden ser rellenadas por las plantillas de vistas. La sintaxis @section{} para esto es limpia y concisa. Razor también tiene la habilidad de permitir comprobar en tiempo de ejecución si una sección particulas ha sido definida, y ofrecer un contenido alternativo  (o incluso un diseño diferente) en caso de que no se indique. Esto ofrece una forma poderosa y fácil de personlizar el aspecto de nuestro sitio - y lo hace más limpio y DRY desde el punto de vista de la implementación.

Espero que sirva.

Scott.

Traducido por: Juan María Laó Ramos.

Artículo original.

9 pensamientos en “ASP.NET MVC 3: Layouts y Secciones con Razor

  1. Pingback: Releases de ASP.NET MVC 3, IIS Express, SQL CE 4, Web Farm Framework, Orchard, WebMatrix « Thinking in .NET

  2. Pingback: ASP.NET MVC 3 y la sintaxis @helper en Razor « Thinking in .NET

  3. Savier

    oie hay alguna forma de anidar layouts? es decir una vista dentro de otra , lo que pasa es que quiero una vista create dentro de una vista list kiero mostrar el form de registro y la lista de x cosas existentes en la misma pagina

    Responder
  4. estrella

    hola.. Alguno me podria ayudar???’ alguien sabe como podria adicionar un script despues de hacer postback en el vista del cliente???

    Responder

Deja un comentario