Diseño en ASP.NET Core

Por Steve Smith y Dave Brock

Las páginas y las vistas a menudo comparten elementos visuales y elementos mediante programación. En este artículo se explica cómo:

  • Usar diseños comunes.
  • Compartir directivas.
  • Ejecutar 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 tema, las diferencias son mínimas:

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

Qué es un diseño

La mayoría de las aplicaciones web tienen un diseño común que ofrece al usuario una experiencia coherente mientras navegan por sus páginas. El diseño suele incluir elementos comunes en la interfaz de usuario, como el encabezado, los elementos de navegación o de menú y el pie de página de la aplicación.

Ejemplo de diseño de página

Las estructuras HTML comunes, como scripts y hojas de estilo, 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 , al que puede hacer referencia cualquier vista utilizada dentro de la aplicación. Los diseños reducen el código duplicado en las vistas.

Por convención, el diseño predeterminado para 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 del Explorador de soluciones

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

    Carpeta Views del Explorador de soluciones

Este diseño define una plantilla de nivel superior para las vistas en la aplicación. Las aplicaciones no requieren un diseño. Las aplicaciones pueden definir más de un diseño, con otras vistas que especifiquen otros diseños.

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

Razor las vistas tienen una Layout propiedad . Las vistas individuales especifican un diseño al configurar esta propiedad:

@{
    Layout = "_Layout";
}

El diseño especificado puede usar una ruta de acceso completa (por ejemplo, /Pages/Shared/_Layout.cshtml o ) o /Views/Shared/_Layout.cshtmlun 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. Primero se busca la carpeta donde existe el método de controlador (o controlador), seguida de la carpeta Shared. Este proceso de detección es idéntico al que se usa para detectar vistas parciales.

De forma predeterminada, todos los diseños deben llamar a RenderBody. Cada vez que se realiza la llamada a RenderBody, se representa 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 permiten organizar dónde se deben colocar determinados elementos de la página. Cada llamada a RenderSection puede especificar si esa sección es obligatoria u opcional:

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

@RenderSection("Scripts", required: false)

Si no se encuentra una sección obligatoria, 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 una vista define una sección, se debe representar (o se producirá un error).

Una definición de ejemplo @section en la Razor vista Páginas:

@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 necesiten este script y no definan una sección de script.

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

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

El marcado anterior se generó mediante scaffolding Identity.

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 desde líneas de código parcialmente ejecutadas, componentes de vista u otros elementos del sistema de vistas.

Omitir secciones

De forma predeterminada, el cuerpo y todas las secciones de una página de contenido deben representarse mediante la página de diseño. El Razor motor de vista aplica esto mediante el seguimiento de si se han representado 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.

Importar directivas compartidas

Las vistas y las páginas pueden usar Razor directivas para importar espacios de nombres y usar la inserción de dependencias. Se pueden especificar varias directivas compartidas por muchas vistas en un archivo _ViewImports.cshtml común. El archivo _ViewImports es compatible con estas directivas:

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

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

Archivo _ViewImports.cshtml de ejemplo:

@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. Los archivos _ViewImports se procesan a partir del nivel de raíz y, después, para cada carpeta que llevó a la ubicación de la propia página o vista. La configuración _ViewImports especificada en el nivel de raíz se puede reemplazar en el nivel de carpeta.

Por ejemplo, supongamos que:

  • 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: todos se ejecutan en orden
  • @tagHelperPrefix: el más cercano a la vista invalida los demás
  • @model: el más cercano a la vista invalida los demás
  • @inherits: el más cercano a la vista invalida los demás
  • @using: todos se incluyen y se omiten los duplicados
  • @inject: para cada propiedad, la más cercana a la vista invalida cualquier otra con 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 que aparecen en _ViewStart.cshtml se ejecutan antes de cada vista completa (no los diseños ni las vistas parciales). Al igual que ViewImports.cshtml, _ViewStart.cshtml es jerárquico. Si un _ViewStart.cshtml archivo se define en la carpeta view o pages, se ejecutará después del definido en la raíz de la carpeta Pages (o Views) (si existe).

Archivo _ViewStart.cshtml de ejemplo:

@{
    Layout = "_Layout";
}

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

_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).