Creación de un diseño coherente en sitios de ASP.NET Web Pages (Razor)

Por Tom FitzMacken

En este artículo se explica cómo puede usar páginas de diseño en un sitio web de ASP.NET Web Pages (Razor) para crear bloques reutilizables de contenido (como encabezados y pies de página) y crear una apariencia coherente para todas las páginas del sitio.

Aprenderá lo siguiente:

  • Crear bloques reutilizables de contenido, como encabezados y pies de página.
  • Crear una búsqueda coherente para todas las páginas del sitio mediante un diseño.
  • Pasar datos en tiempo de ejecución a una página de diseño.

Estas son las características de ASP.NET introducidas en el artículo:

  • Bloques de contenido, que son archivos que contienen contenido con formato HTML que se va a insertar en varias páginas.
  • Páginas de diseño, que son páginas que contienen contenido con formato HTML que puede compartirse mediante páginas del sitio web.
  • Los métodos RenderPage, RenderBody y RenderSection, que indican a ASP.NET dónde insertar elementos de página.
  • El diccionario PageData, que permite compartir datos entre bloques de contenido y páginas de diseño.

Versiones de software usadas en el tutorial

  • ASP.NET Web Pages (Razor) 3

Este tutorial también funciona con ASP.NET Web Pages 2.

Acerca de las páginas de diseño

Muchos sitios web tienen contenido que se muestra en cada página, como un encabezado y pie de página, o un cuadro que indica a los usuarios que han iniciado sesión. ASP.NET permite crear un archivo independiente con un bloque de contenido que pueda contener texto, marcado y código, al igual que una página web normal. Después, puede insertar el bloque de contenido en otras páginas del sitio donde desea que aparezca la información. De este modo, no es necesario copiar y pegar el mismo contenido en todas las páginas. La creación de contenido común como este también facilita la actualización del sitio. Si necesita cambiar el contenido, puede actualizar un solo archivo y los cambios se reflejarán en todas partes en las que se haya insertado el contenido.

En el diagrama siguiente se muestra cómo funcionan los bloques de contenido. Cuando un explorador solicita una página desde el servidor web, ASP.NET inserta los bloques de contenido en el punto en el que se llama al método RenderPage en la página principal. A continuación, la página finalizada (combinada) se envía al explorador.

Conceptual diagram showing how the RenderPage method inserts a referenced page into the current page.

En este procedimiento, creará una página que hará referencia a dos bloques de contenido (un encabezado y un pie de página) que se encuentran en archivos independientes. Puede usar estos mismos bloques de contenido en cualquier página del sitio. Cuando haya terminado, tendrá una página como esta:

Screenshot showing a page in the browser that results from running a page that includes calls to the RenderPage method.

  1. En la carpeta raíz del sitio web, cree un archivo denominado Index.cshtml.

  2. Reemplace el marcado existente por lo siguiente:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Main Page</title>
      </head>
      <body>
    
        <h1>Index Page Content</h1>
        <p>This is the content of the main page.</p>
    
      </body>
    </html>
    
  3. En la carpeta raíz, cree una carpeta denominada Shared.

    Nota:

    Es habitual almacenar archivos que se compartan entre páginas web en una carpeta denominada Shared.

  4. En la carpeta Shared, cree un archivo denominado _Header.cshtml.

  5. Reemplace el contenido existente por lo siguiente:

    <div class="header">This is header text.</div>
    

    Observe que el nombre de archivo es _Header.cshtml, con un carácter de subrayado (_) como prefijo. ASP.NET no enviará ninguna página al explorador si su nombre comienza con un carácter de subrayado. Esto impide que las personas soliciten (de forma voluntaria o no) estas páginas directamente. Es buena idea usar un carácter de subrayado para asignar nombres a las páginas que tienen bloques de contenido, porque en realidad no quiere que los usuarios puedan solicitar estas páginas (existen estrictamente para insertarse en otras páginas).

  6. En la carpeta Shared, cree un archivo denominado _Footer.cshtml y reemplace el contenido por lo siguiente:

    <div class="footer">&copy; 2012 Contoso Pharmaceuticals. All rights reserved.
    </div>
    
  7. En la página Index.cshtml, agregue dos llamadas al método RenderPage, como se muestra aquí:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Main Page</title>
      </head>
      <body>
    
        @RenderPage("~/Shared/_Header.cshtml")
    
        <h1>Index Page Content</h1>
        <p>This is the content of the main page.</p>
    
        @RenderPage("~/Shared/_Footer.cshtml")
    
      </body>
    </html>
    

    Esto muestra cómo insertar un bloque de contenido en una página web. Llame al método RenderPage y pásele el nombre del archivo cuyo contenido desea insertar en ese momento. Aquí va a insertar el contenido de los archivos _Header.cshtml y _Footer.cshtml en el archivo Index.cshtml.

  8. Ejecute la página Index.cshtml en un explorador (en WebMatrix, en el área de trabajo Archivos, haga clic con el botón derecho en el archivo y seleccione Iniciar en el explorador).

  9. En el explorador, vea el origen de la página (por ejemplo, en Internet Explorer, haga clic con el botón derecho en la página y, a continuación, haga clic en Ver origen).

    Esto le permite ver el marcado de página web que se envía al explorador, que combina el marcado de página de índice con los bloques de contenido. En el ejemplo siguiente se muestra el origen de la página que se representa para Index.cshtml. Las llamadas a RenderPage que insertó en Index.cshtml se han reemplazado por el contenido real de los archivos de encabezado y pie de página.

    <!DOCTYPE html>
    <html>
      <head>
        <title>Main Page</title>
      </head>
      <body>
    
      <div class="header">
        This is header text.
      </div>
    
        <h1>Index Page Content</h1>
        <p>This is the content of the main page.</p>
    
      <div class="footer">
        &copy; 2012 Contoso Pharmaceuticals. All rights reserved.
      </div>
    
      </body>
    </html>
    

Creación de una apariencia coherente mediante páginas de diseño

Hasta ahora ha visto que es fácil incluir el mismo contenido en varias páginas. Un enfoque más estructurado para crear una búsqueda coherente de un sitio es usar páginas de diseño. Una página de diseño define la estructura de una página web, pero no contiene ningún contenido real. Después de crear una página de diseño, puede crear páginas web que contengan el contenido y vincularlas a la página de diseño. Cuando se muestren estas páginas, se les dará formato según la página de diseño (en este sentido, una página de diseño actúa como un tipo de plantilla para el contenido definido en otras páginas).

La página de diseño es igual que cualquier página HTML, salvo que contiene una llamada al método RenderBody. La posición del método RenderBody en la página de diseño determina dónde se incluirá la información de la página de contenido.

En el diagrama siguiente se muestra cómo se combinan las páginas de contenido y las páginas de diseño en tiempo de ejecución para generar la página web finalizada. El explorador solicita una página de contenido. La página de contenido tiene código en él que especifica la página de diseño que se va a usar para la estructura de la página. En la página de diseño, el contenido se inserta en el punto donde se llama al método RenderBody. Los bloques de contenido también se pueden insertar en la página de diseño llamando al método RenderPage, de la misma forma en que se hizo en la sección anterior. Una vez completada la página web, se envía al explorador.

Screenshot showing a page in the browser that results from running a page that includes calls to the RenderBody method.

En el procedimiento siguiente se muestra cómo crear una página de diseño y vincularle páginas de contenido.

  1. En la carpeta Shared del sitio web, cree un archivo denominado _Layout1.cshtml.

  2. Reemplace el contenido existente por lo siguiente:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Structured Content </title>
        <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
      </head>
      <body>
        @RenderPage("~/Shared/_Header2.cshtml")
        <div id="main">
          @RenderBody()
        </div>
        <div id="footer">
          &copy; 2012 Contoso Pharmaceuticals. All rights reserved.
        </div>
      </body>
    </html>
    

    Se usa el método RenderPage en una página de diseño para insertar bloques de contenido. Una página de diseño solo puede contener una llamada al método RenderBody.

  3. En la carpeta Shared, cree un archivo denominado _Header2.cshtml y reemplace cualquier contenido existente por lo siguiente:

    <div id="header">Creating a Consistent Look</div>
    
  4. En la carpeta raíz, cree una carpeta y asígnele el nombre Styles.

  5. En la carpeta Styles, cree un archivo denominado Site.css y agregue las siguientes definiciones de estilo:

    h1 {
        border-bottom: 3px solid #cc9900;
        font: 2.75em/1.75em Georgia, serif;
        color: #996600;
    }
    
    ul {
        list-style-type: none;
    }
    
    body {
        margin: 0;
        padding: 1em;
        background-color: #ffffff;
        font: 75%/1.75em "Trebuchet MS", Verdana, sans-serif;
        color: #006600;
    }
    
    #list {
        margin: 1em 0 7em -3em;
        padding: 1em 0 0 0;
        background-color: #ffffff;
        color: #996600;
        width: 25%;
        float: left;
    }
    
    #header, #footer {
        margin: 0;
        padding: 0;
        color: #996600;
    }
    

    Estas definiciones de estilo solo están aquí para mostrar cómo se pueden usar las hojas de estilos con páginas de diseño. Si lo desea, puede definir sus propios estilos para estos elementos.

  6. En la carpeta raíz, cree un archivo denominado Content1.cshtml y reemplace cualquier contenido existente por lo siguiente:

    @{
        Layout = "~/Shared/_Layout1.cshtml";
    }
    
    <h1> Structured Content </h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.</p>
    

    Se trata de una página que usará una página de diseño. El bloque de código de la parte superior de la página indica qué página de diseño se va a usar para dar formato a este contenido.

  7. Ejecute Content1.cshtml en un explorador. La página representada usa el formato y la hoja de estilos definidas en _Layout1.cshtml y el texto (contenido) definido en Content1.cshtml.

    [The screenshot shows running Content 1 dot CSHTML in a browser.]

    Puede repetir el paso 6 para crear más páginas de contenido que luego puedan compartir la misma página de diseño.

    Nota:

    Puede configurar el sitio para que pueda usar automáticamente la misma página de diseño para todas las páginas de contenido de una carpeta. Para obtener más información, consulte Personalización del comportamiento de todo el sitio para ASP.NET Web Pages.

Diseño de páginas de diseño que tienen varias secciones de contenido

Una página de contenido puede tener varias secciones, lo que resulta útil si desea usar diseños que tienen varias áreas con contenido reemplazable. En la página de contenido, asigne a cada sección un nombre único (la sección predeterminada se deja sin nombre). En la página de diseño, agregará un método RenderBody para especificar dónde debe aparecer la sección sin nombre (valor predeterminado). A continuación, agregue métodos RenderSection separados para representar secciones con nombre individualmente.

En el diagrama siguiente se muestra cómo ASP.NET controla el contenido dividido en varias secciones. Cada sección con nombre se incluye en un bloque de secciones de la página de contenido (en el ejemplo se denominan Header y List). El marco inserta la sección de contenido en la página de diseño en el punto en el que se llama al método RenderSection. La sección sin nombre (valor predeterminado) se inserta en el punto en el que se llama al método RenderBody, como se ha visto antes.

Conceptual diagram showing how the RenderSection method inserts references sections into the current page.

En este procedimiento se muestra cómo crear una página de contenido que tenga varias secciones de contenido y cómo representarla mediante una página de diseño que admita varias secciones de contenido.

  1. En la carpeta Shared, cree un archivo denominado _Layout2.cshtml.

  2. Reemplace el contenido existente por lo siguiente:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Multisection Content</title>
        <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
      </head>
      <body>
        <div id="header">
          @RenderSection("header")
        </div>
        <div id="list">
          @RenderSection("list")
        </div>
        <div id="main">
          @RenderBody()
        </div>
        <div id="footer">
          &copy; 2012 Contoso Pharmaceuticals. All rights reserved.
        </div>
      </body>
    </html>
    

    Se usa el método RenderSection para representar las secciones de encabezado y lista.

  3. En la carpeta raíz, cree un archivo denominado Content2.cshtml y reemplace cualquier contenido existente por lo siguiente:

    @{
        Layout = "~/Shared/_Layout2.cshtml";
    }
    
    @section header {
        <div id="header">
            Creating a Consistent Look
        </div>
    }
    
    @section list {
        <ul>
            <li>Lorem</li>
            <li>Ipsum</li>
            <li>Dolor</li>
            <li>Consecte</li>
            <li>Eiusmod</li>
            <li>Tempor</li>
            <li>Incididu</li>
        </ul>
    }
    
    <h1>Multisection Content</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.</p>
    

    Esta página de contenido contiene un bloque de código en la parte superior de la página. Cada sección con nombre se incluye en un bloque de secciones. El resto de la página contiene la sección de contenido predeterminado (sin nombre).

  4. Ejecute Content2.cshtml en un explorador.

    Screenshot showing a page in the browser that results from running a page that includes calls to the RenderSection method.

Cómo hacer opcionales las secciones de contenido

Normalmente, las secciones que cree en una página de contenido deben coincidir con las secciones definidas en la página de diseño. Puede obtener errores si se produce alguno de los siguientes casos:

  • La página de contenido contiene una sección que no tiene ninguna sección correspondiente en la página de diseño.
  • La página de diseño contiene una sección para la que no hay contenido.
  • La página de diseño incluye llamadas de método que intentan representar la misma sección más de una vez.

Sin embargo, puede invalidar este comportamiento para una sección con nombre declarando que la sección es opcional en la página de diseño. Esto le permite definir varias páginas de contenido que pueden compartir una página de diseño, pero que podrían o no tener contenido para una sección específica.

  1. Abra Content2.cshtml y quite la sección siguiente:

    @section header {
      <div id="header">
        Creating a Consistent Look
      </div>
    }
    
  2. Guarde la página y ejecútelo en un explorador. Se muestra un mensaje de error, ya que la página de contenido no proporciona contenido para una sección definida en la página de diseño, es decir, la sección de encabezado.

    Screenshot that shows the error that occurs if you run a page that calls RenderSection method but the corresponding section is not provided.

  3. En la carpeta Shared, abra la página _Layout2.cshtml y reemplace esta línea:

    @RenderSection("header")
    

    con el siguiente código:

    @RenderSection("header", required: false)
    

    Como alternativa, podría reemplazar la línea de código anterior por el siguiente bloque de código, que genera los mismos resultados:

    @if (IsSectionDefined("header")) {
        @RenderSection("header")
    }
    
  4. Vuelva a ejecutar la página Content2.cshtml en un explorador (si todavía tiene esta página abierta en el explorador, puede actualizarla). Esta vez se muestra la página sin ningún error, aunque no tenga ningún encabezado.

Cómo pasar datos a páginas de diseño

Es posible que tenga datos definidos en la página de contenido a la que necesita hacer referencia en una página de diseño. Si es así, debe pasar los datos de la página de contenido a la página de diseño. Por ejemplo, puede que quiera mostrar el estado de inicio de sesión de un usuario, o puede que quiera mostrar u ocultar áreas de contenido en función de la entrada del usuario.

Para pasar datos de una página de contenido a una página de diseño, puede colocar valores en la propiedad PageData de la página de contenido. La propiedad PageData es una colección de pares nombre-valor que contienen los datos que se pueden pasar entre páginas. En la página de diseño, puede leer los valores fuera de la propiedad PageData.

Aquí tiene otro diagrama. En este ejemplo se muestra cómo ASP.NET puede usar la propiedad PageData para pasar valores de una página de contenido a la página de diseño. Cuando ASP.NET comienza a compilar la página web, crea la colección PageData. En la página de contenido, escribirá código para colocar datos en la colección PageData. También se puede acceder a los valores de la colección PageData en otras secciones de la página de contenido o en bloques de contenido adicionales.

Conceptual diagram that shows how a content page can populate a PageData dictionary and pass that information to the layout page.

En el procedimiento siguiente se muestra cómo pasar datos de una página de contenido a una página de diseño. Cuando se ejecuta la página, muestra un botón que permite al usuario ocultar o mostrar una lista definida en la página de diseño. Cuando los usuarios hacen clic en el botón, establece un valor true/false (booleano) en la propiedad PageData. La página de diseño lee ese valor y, si es false, oculta la lista. El valor también se usa en la página de contenido para determinar si se debe mostrar el botón Ocultar lista o el botón Mostrar lista.

[Screenshot shows the Passing Data page.]

  1. En la carpeta raíz, cree un archivo denominado Content3.cshtml y reemplace cualquier contenido existente por lo siguiente:

    @{
        Layout = "~/Shared/_Layout3.cshtml";
    
        PageData["Title"] = "Passing Data";
        PageData["ShowList"] = true;
    
        if (IsPost) {
            if (Request.Form["list"] == "off") {
                PageData["ShowList"] = false;
            }
        }
    }
    
    @section header {
      <div id="header">
        Creating a Consistent Look
      </div>
    }
    
    <h1>@PageData["Title"]</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.</p>
    
    @if (PageData["ShowList"] == true) {
        <form method="post" action="">
          <input type="hidden" name="list" value="off" />
          <input type="submit" value="Hide List" />
        </form>
    }
    else {
        <form method="post" action="">
          <input type="hidden" name="list" value="on" />
          <input type="submit" value="Show List" />
        </form>
    }
    

    El código almacena dos fragmentos de datos en la propiedad PageData: el título de la página web y true o false para especificar si se va a mostrar una lista.

    Tenga en cuenta que ASP.NET permite colocar el marcado HTML en la página de forma condicional mediante un bloque de código. Por ejemplo, el bloque if/else del cuerpo de la página determina qué formulario se va a mostrar en función de si PageData["ShowList"] se establece en true.

  2. En la carpeta Shared, cree un archivo denominado _Layout3.cshtml y reemplace cualquier contenido existente por lo siguiente:

    <!DOCTYPE html>
    <html>
      <head>
        <title>@PageData["Title"]</title>
        <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
      </head>
      <body>
        <div id="header">
          @RenderSection("header")
        </div>
          @if (PageData["ShowList"] == true) {
              <div id="list">
                @RenderPage("~/Shared/_List.cshtml")
              </div>
          }
        <div id="main">
          @RenderBody()
        </div>
        <div id="footer">
          <p>&copy; 2012 Contoso Pharmaceuticals. All rights reserved.</p>
        </div>
      </body>
    </html>
    

    La página de diseño incluye una expresión en el elemento <title> que obtiene el valor de título de la propiedad PageData. También usa el valor ShowList de la propiedad PageData para determinar si se va a mostrar el bloque de contenido de la lista.

  3. En la carpeta Shared, cree un archivo denominado _List.cshtml y reemplace cualquier contenido existente por lo siguiente:

    <ul>
      <li>Lorem</li>
      <li>Ipsum</li>
      <li>Dolor</li>
      <li>Consecte</li>
      <li>Eiusmod</li>
      <li>Tempor</li>
      <li>Incididu</li>
    </ul>
    
  4. Ejecute la página Content3.cshtml en un explorador. La página se muestra con la lista visible en el lado izquierdo y el botón Ocultar lista en la parte inferior.

    Screenshot showing the page that includes the list and a button that says 'Hide List'.

  5. Haga clic en Ocultar lista. La lista desaparece y el botón cambia a Mostrar lista.

    Screenshot showing the page that does not include the list and a button that says 'Show List'.

  6. Haga clic en el botón Mostrar lista y la lista se mostrará de nuevo.

Recursos adicionales

Personalización del comportamiento de todo el sitio para ASP.NET Web Pages