Diseño en ASP.NET Core

Por Steve Smith y Dave Brock

Las páginas e vistas suelen compartir elementos visuales y programáticos. En este artículo se explica cómo:

  • Use diseños comunes.
  • Compartir directivas.
  • Ejecute código común antes de representar páginas o vistas.

En este documento se describen los diseños de los dos enfoques diferentes para ASP.NET Core MVC: Razor Páginas y controladores con vistas. Para este artículo, las diferencias son mínimas:

  • Razor Las páginas están en la carpeta Pages .
  • Los controladores con vistas usan una carpeta Views para las vistas.

¿Qué es un diseño?

La mayoría de las aplicaciones web tienen un diseño común que proporciona al usuario una experiencia coherente a medida que navega de la página a la página. El diseño normalmente incluye elementos comunes de la interfaz de usuario, como el encabezado de la aplicación, los elementos de navegación o de menú, y el pie de página.

Ejemplo de diseño de página

Las estructuras HTML comunes, como scripts y hojas de estilos, también se usan con frecuencia en muchas páginas dentro de una aplicación. Todos estos elementos compartidos se pueden definir en un archivo de diseño , que cualquier vista usada en la aplicación puede hacer referencia a ellos. Los diseños reducen el código duplicado en las vistas.

Por convención, el diseño predeterminado de una aplicación ASP.NET Core se denomina _Layout.cshtml. Los archivos de diseño para los nuevos proyectos de ASP.NET Core creados con las plantillas son:

  • Razor Páginas: Pages/Shared/_Layout.cshtml

    Carpeta Pages en el Explorador de soluciones

  • Controlador con vistas: Views/Shared/_Layout.cshtml

    Carpeta de vistas en el Explorador de Soluciones

El diseño define una plantilla de nivel superior para las vistas de la aplicación. Las aplicaciones no requieren un diseño. Las aplicaciones pueden definir más de un diseño, con vistas diferentes que especifican diseños diferentes.

Este código muestra el archivo de diseño para un proyecto creado mediante plantilla con un controlador y vistas:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - WebApplication1</title>

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
    </environment>
</head>
<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a asp-page="/Index" class="navbar-brand">WebApplication1</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a asp-page="/Index">Home</a></li>
                    <li><a asp-page="/About">About</a></li>
                    <li><a asp-page="/Contact">Contact</a></li>
                </ul>
            </div>
        </div>
    </nav>

    <partial name="_CookieConsentPartial" />

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; 2018 - WebApplication1</p>
        </footer>
    </div>

    <environment include="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    </environment>
    <environment exclude="Development">
        <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT">
        </script>
        <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
                crossorigin="anonymous"
                integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
        </script>
        <script src="~/js/site.min.js" asp-append-version="true"></script>
    </environment>

    @RenderSection("Scripts", required: false)
</body>
</html>

Especificar un diseño

Las vistas de Razor tienen una propiedad Layout. Las vistas individuales especifican un diseño estableciendo esta propiedad:

@{
    Layout = "_Layout";
}

El formato especificado puede usar una ruta de acceso completa (por ejemplo, /Pages/Shared/_Layout.cshtml o /Views/Shared/_Layout.cshtml) o un nombre parcial (ejemplo: _Layout). Cuando se proporciona un nombre parcial, el Razor motor de vista busca el archivo de diseño mediante su proceso de detección estándar. La carpeta donde existe el método de controlador (o controlador) se busca primero, seguida de la carpeta Shared . Este proceso de detección es idéntico al proceso usado para detectar vistas parciales.

De forma predeterminada, todos los diseños deben llamar a RenderBody. Donde sea que se coloque la llamada a RenderBody, se mostrará el contenido de la vista.

Secciones

Opcionalmente, un diseño puede hacer referencia a una o varias secciones mediante una llamada a RenderSection. Las secciones proporcionan una manera de organizar dónde deben colocarse determinados elementos de página. Cada llamada a RenderSection puede especificar si esa sección es necesaria o opcional:

<script type="text/javascript" src="~/scripts/global.js"></script>

@RenderSection("Scripts", required: false)

Si no se encuentra una sección necesaria, se produce una excepción. Las vistas individuales especifican el contenido que se va a representar dentro de una sección mediante la @sectionRazor sintaxis . Si una página o vista define una sección, debe representarse (o se producirá un error).

Ejemplo de definición de @section en una vista de Razor Pages:

@section Scripts {
     <script type="text/javascript" src="~/scripts/main.js"></script>
}

En el código anterior, scripts/main.js se agrega a la scripts sección de una página o vista. Es posible que otras páginas o vistas de la misma aplicación no requieran este script y no definan una sección de scripts.

El marcado siguiente usa el asistente de etiquetas parciales para representar _ValidationScriptsPartial.cshtml:

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

La generación automática de Identity ha generado la sintaxis anterior.

Las secciones definidas en una vista o una vista solo están disponibles en su página de diseño inmediato. No se puede hacer referencia a ellas a través de líneas de código parcialmente ejecutadas, componentes de vista u otros elementos del sistema de vistas.

Omitir secciones

De forma predeterminada, la página de diseño debe representar el cuerpo y todas las secciones de una página de contenido. Para cumplir con esto, el motor de vistas de Razor comprueba si se han renderizado el cuerpo y cada sección.

Para indicar al motor de vistas que pase por alto el cuerpo o las secciones, llame a los métodos IgnoreBody y IgnoreSection.

El cuerpo y todas las secciones de una Razor página deben representarse o omitirse.

Importación de directivas compartidas

Las vistas y las páginas pueden usar directivas de Razor para la importación de espacios de nombres y usar la inserción de dependencias. Las directivas compartidas por muchas vistas pueden especificarse en un archivo común _ViewImports.cshtml . El _ViewImports archivo admite las siguientes directivas:

  • @addTagHelper
  • @removeTagHelper
  • @tagHelperPrefix
  • @using
  • @model
  • @inherits
  • @inject
  • @namespace

El archivo no admite otras Razor características, como funciones y definiciones de sección.

Un archivo de ejemplo _ViewImports.cshtml :

@using WebApplication1
@using WebApplication1.Models
@using WebApplication1.Models.AccountViewModels
@using WebApplication1.Models.ManageViewModels
@using Microsoft.AspNetCore.Identity
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

El _ViewImports.cshtml archivo de una aplicación ASP.NET Core MVC se coloca normalmente en la carpeta Pages (o Views). Un _ViewImports.cshtml archivo se puede colocar dentro de cualquier carpeta, en cuyo caso solo se aplicará a páginas o vistas dentro de esa carpeta y sus subcarpetas. _ViewImports los archivos se procesan a partir del nivel raíz y, a continuación, para cada carpeta que conduce a la ubicación de la página o vista propiamente dicha. _ViewImports Es posible que la configuración especificada en el nivel raíz se invalide en el nivel de carpeta.

Por ejemplo, supongamos:

  • El archivo de nivel _ViewImports.cshtml raíz incluye @model MyModel1 y @addTagHelper *, MyTagHelper1.
  • Un archivo de subcarpeta _ViewImports.cshtml incluye @model MyModel2 y @addTagHelper *, MyTagHelper2.

Las páginas y las vistas de la subcarpeta tendrán acceso a los asistentes de etiquetas y al modelo MyModel2.

Si se encuentran varios _ViewImports.cshtml archivos en la jerarquía de archivos, el comportamiento combinado de las directivas es:

  • @addTagHelper, @removeTagHelper: se ejecutan en orden.
  • @tagHelperPrefix: el más cercano a la vista anula los demás.
  • @model: el más cercano a la vista anula los demás.
  • @inherits: El más cercano a la vista prevalece sobre los demás.
  • @using: se incluyen todos; se omiten los duplicados.
  • @inject: Para cada propiedad, la más cercana a la vista anula a cualquier otra que tenga el mismo nombre de propiedad.

Ejecutar código antes de cada vista

El código que debe ejecutarse antes de que cada vista o página se coloque en el _ViewStart.cshtml archivo. Por convención, el _ViewStart.cshtml archivo se encuentra en la carpeta Pages (o Views). Las instrucciones enumeradas en _ViewStart.cshtml se ejecutan antes de cada vista completa (no diseños y no vistas parciales). Al igual que ViewImports.cshtml, _ViewStart.cshtml es jerárquico. Si se define un _ViewStart.cshtml archivo en la carpeta view o pages, se ejecutará después del definido en la raíz de la carpeta Pages (o Views) (si existe).

Un archivo de ejemplo _ViewStart.cshtml :

@{
    Layout = "_Layout";
}

El archivo anterior especifica que todas las vistas usarán el _Layout.cshtml diseño.

_ViewStart.cshtml y _ViewImports.cshtmlno suelen colocarse en la carpeta /Pages/Shared (o /Views/Shared). Las versiones de nivel de aplicación de estos archivos deben colocarse directamente en la carpeta /Pages (o /Views).