Páginas de Razor con scaffolding en ASP.NET CoreScaffolded Razor Pages in ASP.NET Core

Por Rick AndersonBy Rick Anderson

En este tutorial se examinan las páginas de Razor creadas por la técnica scaffolding en el tutorial anterior.This tutorial examines the Razor Pages created by scaffolding in the previous tutorial.

Páginas de creación, eliminación, detalles y ediciónThe Create, Delete, Details, and Edit pages

Examine el modelo de página Pages/Movies/Index.cshtml.cs:Examine the Pages/Movies/Index.cshtml.cs Page Model:

// Unused usings removed.
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace RazorPagesMovie.Pages.Movies
{
    public class IndexModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }

        public IList<Movie> Movie { get;set; }

        public async Task OnGetAsync()
        {
            Movie = await _context.Movie.ToListAsync();
        }
    }
}

Las páginas de Razor se derivan de PageModel.Razor Pages are derived from PageModel. Por convención, la clase derivada de PageModel se denomina <PageName>Model.By convention, the PageModel-derived class is called <PageName>Model. El constructor aplica la inserción de dependencias para agregar el RazorPagesMovieContext a la página.The constructor uses dependency injection to add the RazorPagesMovieContext to the page. Todas las páginas con scaffolding siguen este patrón.All the scaffolded pages follow this pattern. Vea Código asincrónico para obtener más información sobre programación asincrónica con Entity Framework.See Asynchronous code for more information on asynchronous programming with Entity Framework.

Cuando se efectúa una solicitud para la página, el método OnGetAsync devuelve una lista de películas a la página de Razor.When a request is made for the page, the OnGetAsync method returns a list of movies to the Razor Page. Se llama a OnGetAsync o OnGet para inicializar el estado de la página.OnGetAsync or OnGet is called to initialize the state of the page. En este caso, OnGetAsync obtiene una lista de películas y las muestra.In this case, OnGetAsync gets a list of movies and displays them.

Cuando OnGet devuelve void o OnGetAsync devuelve Task, no se utiliza ninguna instrucción de devolución.When OnGet returns void or OnGetAsync returnsTask, no return statement is used. Cuando el tipo de valor devuelto es IActionResult o Task<IActionResult>, se debe proporcionar una instrucción return.When the return type is IActionResult or Task<IActionResult>, a return statement must be provided. Por ejemplo, el método OnPostAsync Pages/Movies/Create.cshtml.cs:For example, the Pages/Movies/Create.cshtml.cs OnPostAsync method:

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Movie.Add(Movie);
        await _context.SaveChangesAsync();

        return RedirectToPage("./Index");
    }
}

Examine la página de Razor Pages/Movies/Index.cshtml:Examine the Pages/Movies/Index.cshtml Razor Page:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Movie) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Razor puede realizar la transición de HTML a C# o a un marcado específico de Razor.Razor can transition from HTML into C# or into Razor-specific markup. Cuando el símbolo @ va seguido de una palabra clave reservada de Razor, realiza una transición a un marcado específico de Razor; en caso contrario, realiza la transición a C#.When an @ symbol is followed by a Razor reserved keyword, it transitions into Razor-specific markup, otherwise it transitions into C#.

La directiva @pageThe @page directive

La directiva de Razor @page convierte el archivo en una acción de MVC, lo que significa que puede administrar las solicitudes.The @page Razor directive makes the file an MVC action, which means that it can handle requests. @page debe ser la primera directiva de Razor de una página.@page must be the first Razor directive on a page. @page es un ejemplo de la transición a un marcado específico de Razor.@page is an example of transitioning into Razor-specific markup. Vea Razor syntax (Sintaxis de Razor) para más información.See Razor syntax for more information.

Examine la expresión lambda usada en el siguiente asistente de HTML:Examine the lambda expression used in the following HTML Helper:

@Html.DisplayNameFor(model => model.Movie[0].Title)

El asistente de HTML DisplayNameFor inspecciona la propiedad Title a la que se hace referencia en la expresión lambda para determinar el nombre para mostrar.The DisplayNameFor HTML Helper inspects the Title property referenced in the lambda expression to determine the display name. La expresión lambda se inspecciona, no se evalúa.The lambda expression is inspected rather than evaluated. Esto significa que no hay ninguna infracción de acceso si model, model.Movie o model.Movie[0] son null o están vacíos.That means there is no access violation when model, model.Movie, or model.Movie[0] is null or empty. Al evaluar la expresión lambda (por ejemplo, con @Html.DisplayFor(modelItem => item.Title)), se evalúan los valores de propiedad del modelo.When the lambda expression is evaluated (for example, with @Html.DisplayFor(modelItem => item.Title)), the model's property values are evaluated.

La directiva @modelThe @model directive

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

La directiva @model especifica el tipo del modelo que se pasa a la página de Razor.The @model directive specifies the type of the model passed to the Razor Page. En el ejemplo anterior, la línea @model permite que la clase derivada de PageModel esté disponible en la página de Razor.In the preceding example, the @model line makes the PageModel-derived class available to the Razor Page. El modelo se usa en los asistentes de HTML @Html.DisplayNameFor y @Html.DisplayFor de la página.The model is used in the @Html.DisplayNameFor and @Html.DisplayFor HTML Helpers on the page.

Página de diseñoThe layout page

Seleccione los vínculos de menú (RazorPagesMovie [Película de Razor Pages], Home [Inicio] y Privacy [Privacidad]).Select the menu links (RazorPagesMovie, Home, and Privacy). Cada página muestra el mismo diseño de menú.Each page shows the same menu layout. El diseño de menú se implementa en el archivo Pages/Shared/_Layout.cshtml.The menu layout is implemented in the Pages/Shared/_Layout.cshtml file. Abra el archivo Pages/Shared/_Layout.cshtml.Open the Pages/Shared/_Layout.cshtml file.

Las plantillas de diseño permiten que el diseño del contenedor HTML:Layout templates allow the HTML container layout to be:

  • Esté especificado en un solo lugr.Specified in one place.
  • Se aplique en varias páginas del sitio.Applied in multiple pages in the site.

Busque la línea @RenderBody().Find the @RenderBody() line. RenderBody es un marcador de posición donde se muestran todas las vistas específicas de página, encapsuladas en la página de diseño.RenderBody is a placeholder where all the page-specific views show up, wrapped in the layout page. Por ejemplo, seleccione el vínculo Privacidad y la vista Pages/Privacy.cshtml se representa dentro del método RenderBody.For example, select the Privacy link and the Pages/Privacy.cshtml view is rendered inside the RenderBody method.

Propiedades ViewData y LayoutViewData and layout

Tenga en cuenta el siguiente marcado del archivo Pages/Movies/Index.cshtml:Consider the following markup from the Pages/Movies/Index.cshtml file:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

El marcado resaltado anterior es un ejemplo de Razor con una transición a C#.The preceding highlighted markup is an example of Razor transitioning into C#. Los caracteres { y } delimitan un bloque de código de C#.The { and } characters enclose a block of C# code.

La clase base PageModel contiene una propiedad de diccionario ViewData que se puede usar para pasar datos a una vista.The PageModel base class contains a ViewData dictionary property that can be used to pass data to a View. Los objetos se agregan al diccionario ViewData con un patrón clave-valor.Objects are added to the ViewData dictionary using a key/value pattern. En el ejemplo anterior, la propiedad "Title" se agrega al diccionario ViewData.In the preceding sample, the "Title" property is added to the ViewData dictionary.

La propiedad "Title" se usa en el archivo Pages/Shared/_Layout.cshtml.The "Title" property is used in the Pages/Shared/_Layout.cshtml file. En el siguiente marcado se muestran las primeras líneas del archivo _Layout.cshtml.The following markup shows the first few lines of the _Layout.cshtml file.

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

    @*Markup removed for brevity.*@

La línea @*Markup removed for brevity.*@ es un comentario de Razor.The line @*Markup removed for brevity.*@ is a Razor comment. A diferencia de los comentarios HTML (<!-- -->), los comentarios de Razor no se envían al cliente.Unlike HTML comments (<!-- -->), Razor comments are not sent to the client.

Actualizar el diseñoUpdate the layout

Cambie el elemento <title> del archivo Pages/Shared/_Layout.cshtml para mostrar Movie en lugar de RazorPagesMovie.Change the <title> element in the Pages/Shared/_Layout.cshtml file to display Movie rather than RazorPagesMovie.

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

Busque el siguiente elemento delimitador en el archivo Pages/Shared/_Layout.cshtml.Find the following anchor element in the Pages/Shared/_Layout.cshtml file.

<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>

Reemplace el elemento anterior por el marcado siguiente:Replace the preceding element with the following markup:

<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>

El elemento delimitador anterior es un asistente de etiquetas.The preceding anchor element is a Tag Helper. En este caso, se trata de el asistente de etiquetas Anchor.In this case, it's the Anchor Tag Helper. El atributo y valor del asistente de etiquetas asp-page="/Movies/Index" crea un vínculo a la página de Razor /Movies/Index.The asp-page="/Movies/Index" Tag Helper attribute and value creates a link to the /Movies/Index Razor Page. El valor de atributo asp-area está vacío, por lo que no se usa el área del vínculo.The asp-area attribute value is empty, so the area isn't used in the link. Consulte Áreas para obtener más información.See Areas for more information.

Guarde los cambios y pruebe la aplicación haciendo clic en el vínculo RpMovie.Save your changes, and test the app by clicking on the RpMovie link. Si tiene cualquier problema, consulte el archivo _Layout.cshtml en GitHub.See the _Layout.cshtml file in GitHub if you have any problems.

Pruebe los otros vínculos (Inicio, RpMovie, Crear, Editar y Eliminar).Test the other links (Home, RpMovie, Create, Edit, and Delete). Cada página establece el título, que puede ver en la pestaña del explorador. Al marcar una página, se usa el título para el marcador.Each page sets the title, which you can see in the browser tab. When you bookmark a page, the title is used for the bookmark.

Nota

Es posible que no pueda escribir comas decimales en el campo Price.You may not be able to enter decimal commas in the Price field. Para que la validación de jQuery sea compatible con configuraciones regionales distintas del inglés que usan una coma (",") en lugar de un punto decimal y formatos de fecha distintos del de Estados Unidos, debe seguir unos pasos para globalizar la aplicación.To support jQuery validation for non-English locales that use a comma (",") for a decimal point, and non US-English date formats, you must take steps to globalize your app. Consulte este problema 4076 de GitHub para instrucciones sobre cómo agregar la coma decimal.See this GitHub issue 4076 for instructions on adding decimal comma.

La propiedad Layout se establece en el archivo Pages/_ViewStart.cshtml:The Layout property is set in the Pages/_ViewStart.cshtml file:

@{
    Layout = "_Layout";
}

El marcado anterior establece el archivo de diseño en Pages/Shared/_Layout.cshtml para todos los archivos de Razor en la carpeta Pages.The preceding markup sets the layout file to Pages/Shared/_Layout.cshtml for all Razor files under the Pages folder. Vea Layout (Diseño) para más información.See Layout for more information.

Modelo de página CrearThe Create page model

Examine el modelo de página Pages/Movies/Create.cshtml.cs:Examine the Pages/Movies/Create.cshtml.cs page model:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
using System;
using System.Threading.Tasks;

namespace RazorPagesMovie.Pages.Movies
{
    public class CreateModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }

        public IActionResult OnGet()
        {
            return Page();
        }

        [BindProperty]
        public Movie Movie { get; set; }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _context.Movie.Add(Movie);
            await _context.SaveChangesAsync();

            return RedirectToPage("./Index");
        }
    }
}

El método OnGet inicializa cualquier estado necesario para la página.The OnGet method initializes any state needed for the page. La página Crear no tiene ningún estado que inicializar, de modo que se devuelve Page.The Create page doesn't have any state to initialize, so Page is returned. Más adelante en el tutorial se muestra un ejemplo del estado de inicialización de OnGet.Later in the tutorial, an example of OnGet initializing state is shown. El método Page crea un objeto PageResult que representa la página Create.cshtml.The Page method creates a PageResult object that renders the Create.cshtml page.

La propiedad Movie usa el atributo [BindProperty] para participar en el enlace de modelos.The Movie property uses the [BindProperty] attribute to opt-in to model binding. Cuando el formulario de creación publica los valores del formulario, el tiempo de ejecución de ASP.NET Core enlaza los valores publicados con el modelo Movie.When the Create form posts the form values, the ASP.NET Core runtime binds the posted values to the Movie model.

El método OnPostAsync se ejecuta cuando la página publica los datos del formulario:The OnPostAsync method is run when the page posts form data:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Si hay algún error de modelo, se vuelve a mostrar el formulario, junto con los datos del formulario publicados.If there are any model errors, the form is redisplayed, along with any form data posted. La mayoría de los errores de modelo se pueden capturar en el cliente antes de que se publique el formulario.Most model errors can be caught on the client-side before the form is posted. Un ejemplo de un error de modelo consiste en publicar un valor para el campo de fecha que no se puede convertir en una fecha.An example of a model error is posting a value for the date field that cannot be converted to a date. Más adelante en el tutorial, hablaremos de la validación del lado cliente y de la validación de modelos.Client-side validation and model validation are discussed later in the tutorial.

Si no hay ningún error de modelo, los datos se guardan y el explorador se redirige a la página Índice.If there are no model errors, the data is saved, and the browser is redirected to the Index page.

Página de Razor CrearThe Create Razor Page

Examine el archivo de la página de Razor Pages/Movies/Create.cshtml:Examine the Pages/Movies/Create.cshtml Razor Page file:

@page
@model RazorPagesMovie.Pages.Movies.CreateModel

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Movie.Title" class="control-label"></label>
                <input asp-for="Movie.Title" class="form-control" />
                <span asp-validation-for="Movie.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.ReleaseDate" class="control-label"></label>
                <input asp-for="Movie.ReleaseDate" class="form-control" />
                <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Genre" class="control-label"></label>
                <input asp-for="Movie.Genre" class="form-control" />
                <span asp-validation-for="Movie.Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Price" class="control-label"></label>
                <input asp-for="Movie.Price" class="form-control" />
                <span asp-validation-for="Movie.Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Visual Studio muestra las etiquetas siguientes con una fuente negrita diferenciada que se aplica a los asistentes de etiquetas:Visual Studio displays the following tags in a distinctive bold font used for Tag Helpers:

  • <form method="post">
  • <div asp-validation-summary="ModelOnly" class="text-danger"></div>
  • <label asp-for="Movie.Title" class="control-label"></label>
  • <input asp-for="Movie.Title" class="form-control" />
  • <span asp-validation-for="Movie.Title" class="text-danger"></span>

Vista de VS17 de la página Create.cshtml

El elemento <form method="post"> es un asistente de etiquetas de formulario.The <form method="post"> element is a Form Tag Helper. El asistente de etiquetas de formulario incluye automáticamente un token antifalsificación.The Form Tag Helper automatically includes an antiforgery token.

El motor de scaffolding crea un marcado de Razor para cada campo del modelo (excepto el identificador) similar al siguiente:The scaffolding engine creates Razor markup for each field in the model (except the ID) similar to the following:

<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
    <label asp-for="Movie.Title" class="control-label"></label>
    <input asp-for="Movie.Title" class="form-control" />
    <span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>

Los asistentes de etiquetas de validación (<div asp-validation-summary y <span asp-validation-for) muestran errores de validación.The Validation Tag Helpers (<div asp-validation-summary and <span asp-validation-for) display validation errors. La validación se trata con más detalle en un punto posterior de esta serie.Validation is covered in more detail later in this series.

El asistente de etiquetas (<label asp-for="Movie.Title" class="control-label"></label>) genera el título de la etiqueta y el atributo for para la propiedad Title.The Label Tag Helper (<label asp-for="Movie.Title" class="control-label"></label>) generates the label caption and for attribute for the Title property.

El asistente de etiquetas de entrada (<input asp-for="Movie.Title" class="form-control">) usa los atributos DataAnnotations y genera los atributos HTML necesarios para la validación de jQuery en el lado del cliente.The Input Tag Helper (<input asp-for="Movie.Title" class="form-control">) uses the DataAnnotations attributes and produces HTML attributes needed for jQuery Validation on the client-side.

Para obtener más información sobre los asistentes de etiquetas como <form method="post">, consulte Asistentes de etiquetas en ASP.NET Core.For more information on Tag Helpers such as <form method="post">, see Tag Helpers in ASP.NET Core.

Recursos adicionalesAdditional resources

Por Rick AndersonBy Rick Anderson

En este tutorial se examinan las páginas de Razor creadas por la técnica scaffolding en el tutorial anterior.This tutorial examines the Razor Pages created by scaffolding in the previous tutorial.

Vea o descargue un ejemplo.View or download sample.

Páginas de creación, eliminación, detalles y ediciónThe Create, Delete, Details, and Edit pages

Examine el modelo de página Pages/Movies/Index.cshtml.cs:Examine the Pages/Movies/Index.cshtml.cs Page Model:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;

namespace RazorPagesMovie.Pages.Movies
{
    public class IndexModel : PageModel
    {
        private readonly RazorPagesMovie.Models.RazorPagesMovieContext _context;

        public IndexModel(RazorPagesMovie.Models.RazorPagesMovieContext context)
        {
            _context = context;
        }

        public IList<Movie> Movie { get;set; }

        public async Task OnGetAsync()
        {
            Movie = await _context.Movie.ToListAsync();
        }
    }
}

Las páginas de Razor se derivan de PageModel.Razor Pages are derived from PageModel. Por convención, la clase derivada de PageModel se denomina <PageName>Model.By convention, the PageModel-derived class is called <PageName>Model. El constructor aplica la inserción de dependencias para agregar el RazorPagesMovieContext a la página.The constructor uses dependency injection to add the RazorPagesMovieContext to the page. Todas las páginas con scaffolding siguen este patrón.All the scaffolded pages follow this pattern. Vea Código asincrónico para obtener más información sobre programación asincrónica con Entity Framework.See Asynchronous code for more information on asynchronous programming with Entity Framework.

Cuando se efectúa una solicitud para la página, el método OnGetAsync devuelve una lista de películas a la página de Razor.When a request is made for the page, the OnGetAsync method returns a list of movies to the Razor Page. Se llama a OnGetAsync o a OnGet en una página de Razor para inicializar el estado de la página.OnGetAsync or OnGet is called on a Razor Page to initialize the state for the page. En este caso, OnGetAsync obtiene una lista de películas y las muestra.In this case, OnGetAsync gets a list of movies and displays them.

Cuando OnGet devuelve void o OnGetAsync devuelve Task, no se utiliza ningún método de devolución.When OnGet returns void or OnGetAsync returnsTask, no return method is used. Cuando el tipo de valor devuelto es IActionResult o Task<IActionResult>, se debe proporcionar una instrucción return.When the return type is IActionResult or Task<IActionResult>, a return statement must be provided. Por ejemplo, el método OnPostAsync Pages/Movies/Create.cshtml.cs:For example, the Pages/Movies/Create.cshtml.cs OnPostAsync method:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Examine la página de Razor Pages/Movies/Index.cshtml:Examine the Pages/Movies/Index.cshtml Razor Page:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Movie) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Razor puede realizar la transición de HTML a C# o a un marcado específico de Razor.Razor can transition from HTML into C# or into Razor-specific markup. Cuando el símbolo @ va seguido de una palabra clave reservada de Razor, realiza una transición a un marcado específico de Razor; en caso contrario, realiza la transición a C#.When an @ symbol is followed by a Razor reserved keyword, it transitions into Razor-specific markup, otherwise it transitions into C#.

La directiva de Razor @page convierte el archivo en una acción de MVC, lo que significa que puede controlar las solicitudes.The @page Razor directive makes the file into an MVC action, which means that it can handle requests. @page debe ser la primera directiva de Razor de una página.@page must be the first Razor directive on a page. @page es un ejemplo de la transición a un marcado específico de Razor.@page is an example of transitioning into Razor-specific markup. Vea Razor syntax (Sintaxis de Razor) para más información.See Razor syntax for more information.

Examine la expresión lambda usada en el siguiente asistente de HTML:Examine the lambda expression used in the following HTML Helper:

@Html.DisplayNameFor(model => model.Movie[0].Title)

El asistente de HTML DisplayNameFor inspecciona la propiedad Title a la que se hace referencia en la expresión lambda para determinar el nombre para mostrar.The DisplayNameFor HTML Helper inspects the Title property referenced in the lambda expression to determine the display name. La expresión lambda se inspecciona, no se evalúa.The lambda expression is inspected rather than evaluated. Esto significa que no hay ninguna infracción de acceso si model, model.Movie o model.Movie[0] son null o están vacíos.That means there is no access violation when model, model.Movie, or model.Movie[0] are null or empty. Al evaluar la expresión lambda (por ejemplo, con @Html.DisplayFor(modelItem => item.Title)), se evalúan los valores de propiedad del modelo.When the lambda expression is evaluated (for example, with @Html.DisplayFor(modelItem => item.Title)), the model's property values are evaluated.

La directiva @modelThe @model directive

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

La directiva @model especifica el tipo del modelo que se pasa a la página de Razor.The @model directive specifies the type of the model passed to the Razor Page. En el ejemplo anterior, la línea @model permite que la clase derivada de PageModel esté disponible en la página de Razor.In the preceding example, the @model line makes the PageModel-derived class available to the Razor Page. El modelo se usa en los asistentes de HTML @Html.DisplayNameFor y @Html.DisplayFor de la página.The model is used in the @Html.DisplayNameFor and @Html.DisplayFor HTML Helpers on the page.

Página de diseñoThe layout page

Seleccione los vínculos de menú (RazorPagesMovie [Película de Razor Pages], Home [Inicio] y Privacy [Privacidad]).Select the menu links (RazorPagesMovie, Home, and Privacy). Cada página muestra el mismo diseño de menú.Each page shows the same menu layout. El diseño de menú se implementa en el archivo Pages/Shared/_Layout.cshtml.The menu layout is implemented in the Pages/Shared/_Layout.cshtml file. Abra el archivo Pages/Shared/_Layout.cshtml.Open the Pages/Shared/_Layout.cshtml file.

Las plantillas de diseño permiten especificar el diseño del contenedor HTML del sitio en un solo lugar y, después, aplicarlo en varias páginas del sitio.Layout templates allow you to specify the HTML container layout of your site in one place and then apply it across multiple pages in your site. Busque la línea @RenderBody().Find the @RenderBody() line. RenderBody es un marcador de posición donde se mostrarán todas las vistas específicas de página que cree, encapsuladas en la página de diseño.RenderBody is a placeholder where all the page-specific views you create show up, wrapped in the layout page. Por ejemplo, si selecciona el vínculo Privacy (Privacidad), la vista Pages/Privacy.cshtml se representará dentro del método RenderBody.For example, if you select the Privacy link, the Pages/Privacy.cshtml view is rendered inside the RenderBody method.

Propiedades ViewData y LayoutViewData and layout

Tenga en cuenta el siguiente código del archivo Pages/Movies/Index.cshtml:Consider the following code from the Pages/Movies/Index.cshtml file:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

El código resaltado anterior es un ejemplo de Razor con una transición a C#.The preceding highlighted code is an example of Razor transitioning into C#. Los caracteres { y } delimitan un bloque de código de C#.The { and } characters enclose a block of C# code.

La clase base PageModel tiene una propiedad de diccionario ViewData que se puede usar para agregar datos que quiera pasar a una vista.The PageModel base class has a ViewData dictionary property that can be used to add data that you want to pass to a View. Puede agregar objetos al diccionario ViewData con un patrón de clave/valor.You add objects into the ViewData dictionary using a key/value pattern. En el ejemplo anterior, se agrega la propiedad "Title" al diccionario ViewData.In the preceding sample, the "Title" property is added to the ViewData dictionary.

La propiedad "Title" se usa en el archivo Pages/Shared/_Layout.cshtml.The "Title" property is used in the Pages/Shared/_Layout.cshtml file. En el siguiente marcado se muestran las primeras líneas del archivo _Layout.cshtml.The following markup shows the first few lines of the _Layout.cshtml file.

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

    @*Markup removed for brevity.*@

La línea @*Markup removed for brevity.*@ es un comentario de Razor que no aparece en el archivo de diseño.The line @*Markup removed for brevity.*@ is a Razor comment which doesn't appear in your layout file. A diferencia de los comentarios HTML (<!-- -->), los comentarios de Razor no se envían al cliente.Unlike HTML comments (<!-- -->), Razor comments are not sent to the client.

Actualizar el diseñoUpdate the layout

Cambie el elemento <title> del archivo Pages/Shared/_Layout.cshtml para mostrar Movie en lugar de RazorPagesMovie.Change the <title> element in the Pages/Shared/_Layout.cshtml file to display Movie rather than RazorPagesMovie.

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

Busque el siguiente elemento delimitador en el archivo Pages/Shared/_Layout.cshtml.Find the following anchor element in the Pages/Shared/_Layout.cshtml file.

<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>

Reemplace el elemento anterior por el marcado siguiente.Replace the preceding element with the following markup.

<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>

El elemento delimitador anterior es un asistente de etiquetas.The preceding anchor element is a Tag Helper. En este caso, se trata de el asistente de etiquetas Anchor.In this case, it's the Anchor Tag Helper. El atributo y valor del asistente de etiquetas asp-page="/Movies/Index" crea un vínculo a la página de Razor /Movies/Index.The asp-page="/Movies/Index" Tag Helper attribute and value creates a link to the /Movies/Index Razor Page. El valor de atributo asp-area está vacío, por lo que no se usa el área del vínculo.The asp-area attribute value is empty, so the area isn't used in the link. Consulte Áreas para obtener más información.See Areas for more information.

Guarde los cambios y pruebe la aplicación haciendo clic en el vínculo RpMovie.Save your changes, and test the app by clicking on the RpMovie link. Si tiene cualquier problema, consulte el archivo _Layout.cshtml en GitHub.See the _Layout.cshtml file in GitHub if you have any problems.

Pruebe los otros vínculos (Inicio, RpMovie, Crear, Editar y Eliminar).Test the other links (Home, RpMovie, Create, Edit, and Delete). Cada página establece el título, que puede ver en la pestaña del explorador. Al marcar una página, se usa el título para el marcador.Each page sets the title, which you can see in the browser tab. When you bookmark a page, the title is used for the bookmark.

Nota

Es posible que no pueda escribir comas decimales en el campo Price.You may not be able to enter decimal commas in the Price field. Para que la validación de jQuery sea compatible con configuraciones regionales distintas del inglés que usan una coma (",") en lugar de un punto decimal y formatos de fecha distintos del de Estados Unidos, debe seguir unos pasos para globalizar la aplicación.To support jQuery validation for non-English locales that use a comma (",") for a decimal point, and non US-English date formats, you must take steps to globalize your app. Consulte el problema 4076 de GitHub para obtener instrucciones sobre cómo agregar la coma decimal.This GitHub issue 4076 for instructions on adding decimal comma.

La propiedad Layout se establece en el archivo Pages/_ViewStart.cshtml:The Layout property is set in the Pages/_ViewStart.cshtml file:

@{
    Layout = "_Layout";
}

El marcado anterior establece el archivo de diseño en Pages/Shared/_Layout.cshtml para todos los archivos de Razor en la carpeta Pages.The preceding markup sets the layout file to Pages/Shared/_Layout.cshtml for all Razor files under the Pages folder. Vea Layout (Diseño) para más información.See Layout for more information.

Modelo de página CrearThe Create page model

Examine el modelo de página Pages/Movies/Create.cshtml.cs:Examine the Pages/Movies/Create.cshtml.cs page model:

// Unused usings removed.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
using System;
using System.Threading.Tasks;

namespace RazorPagesMovie.Pages.Movies
{
    public class CreateModel : PageModel
    {
        private readonly RazorPagesMovie.Models.RazorPagesMovieContext _context;

        public CreateModel(RazorPagesMovie.Models.RazorPagesMovieContext context)
        {
            _context = context;
        }

        public IActionResult OnGet()
        {
            return Page();
        }

        [BindProperty]
        public Movie Movie { get; set; }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _context.Movie.Add(Movie);
            await _context.SaveChangesAsync();

            return RedirectToPage("./Index");
        }
    }
}

El método OnGet inicializa cualquier estado necesario para la página.The OnGet method initializes any state needed for the page. La página Crear no tiene ningún estado que inicializar, de modo que se devuelve Page.The Create page doesn't have any state to initialize, so Page is returned. Más adelante en el tutorial veremos el estado de inicialización del método OnGet.Later in the tutorial you see OnGet method initialize state. El método Page crea un objeto PageResult que representa la página Create.cshtml.The Page method creates a PageResult object that renders the Create.cshtml page.

La propiedad Movie usa el atributo [BindProperty] para participar en el enlace de modelos.The Movie property uses the [BindProperty] attribute to opt-in to model binding. Cuando el formulario de creación publica los valores del formulario, el tiempo de ejecución de ASP.NET Core enlaza los valores publicados con el modelo Movie.When the Create form posts the form values, the ASP.NET Core runtime binds the posted values to the Movie model.

El método OnPostAsync se ejecuta cuando la página publica los datos del formulario:The OnPostAsync method is run when the page posts form data:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Si hay algún error de modelo, se vuelve a mostrar el formulario, junto con los datos del formulario publicados.If there are any model errors, the form is redisplayed, along with any form data posted. La mayoría de los errores de modelo se pueden capturar en el cliente antes de que se publique el formulario.Most model errors can be caught on the client-side before the form is posted. Un ejemplo de un error de modelo consiste en publicar un valor para el campo de fecha que no se puede convertir en una fecha.An example of a model error is posting a value for the date field that cannot be converted to a date. Más adelante en el tutorial, hablaremos de la validación del lado cliente y de la validación de modelos.Client-side validation and model validation are discussed later in the tutorial.

Si no hay ningún error de modelo, los datos se guardan y el explorador se redirige a la página Índice.If there are no model errors, the data is saved, and the browser is redirected to the Index page.

Página de Razor CrearThe Create Razor Page

Examine el archivo de la página de Razor Pages/Movies/Create.cshtml:Examine the Pages/Movies/Create.cshtml Razor Page file:

@page
@model RazorPagesMovie.Pages.Movies.CreateModel

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Movie.Title" class="control-label"></label>
                <input asp-for="Movie.Title" class="form-control" />
                <span asp-validation-for="Movie.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.ReleaseDate" class="control-label"></label>
                <input asp-for="Movie.ReleaseDate" class="form-control" />
                <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Genre" class="control-label"></label>
                <input asp-for="Movie.Genre" class="form-control" />
                <span asp-validation-for="Movie.Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Price" class="control-label"></label>
                <input asp-for="Movie.Price" class="form-control" />
                <span asp-validation-for="Movie.Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Visual Studio muestra la etiqueta <form method="post"> con una fuente negrita diferenciada que se aplica a los asistentes de etiquetas:Visual Studio displays the <form method="post"> tag in a distinctive bold font used for Tag Helpers:

Vista de VS17 de la página Create.cshtml

El elemento <form method="post"> es un asistente de etiquetas de formulario.The <form method="post"> element is a Form Tag Helper. El asistente de etiquetas de formulario incluye automáticamente un token antifalsificación.The Form Tag Helper automatically includes an antiforgery token.

El motor de scaffolding crea un marcado de Razor para cada campo del modelo (excepto el identificador) similar al siguiente:The scaffolding engine creates Razor markup for each field in the model (except the ID) similar to the following:

<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
    <label asp-for="Movie.Title" class="control-label"></label>
    <input asp-for="Movie.Title" class="form-control" />
    <span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>

Los asistentes de etiquetas de validación (<div asp-validation-summary y <span asp-validation-for) muestran errores de validación.The Validation Tag Helpers (<div asp-validation-summary and <span asp-validation-for) display validation errors. La validación se trata con más detalle en un punto posterior de esta serie.Validation is covered in more detail later in this series.

El asistente de etiquetas (<label asp-for="Movie.Title" class="control-label"></label>) genera el título de la etiqueta y el atributo for para la propiedad Title.The Label Tag Helper (<label asp-for="Movie.Title" class="control-label"></label>) generates the label caption and for attribute for the Title property.

El asistente de etiquetas de entrada (<input asp-for="Movie.Title" class="form-control">) usa los atributos DataAnnotations y genera los atributos HTML necesarios para la validación de jQuery en el lado del cliente.The Input Tag Helper (<input asp-for="Movie.Title" class="form-control">) uses the DataAnnotations attributes and produces HTML attributes needed for jQuery Validation on the client-side.

Recursos adicionalesAdditional resources