Parte 3, com Scaffold Razor páginas em ASP.NET CorePart 3, scaffolded Razor Pages in ASP.NET Core

De Rick AndersonBy Rick Anderson

Este tutorial examina as Razor páginas criadas por scaffolding no tutorial anterior.This tutorial examines the Razor Pages created by scaffolding in the previous tutorial.

As páginas Create, Delete, Details e EditThe Create, Delete, Details, and Edit pages

Examine o modelo de página páginas/filmes/ 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();
        }
    }
}

Razor As páginas são derivadas de PageModel .Razor Pages are derived from PageModel. Por convenção, a PageModel classe derivada é nomeada <PageName>Model .By convention, the PageModel-derived class is named <PageName>Model. O construtor usa injeção de dependência para adicionar o RazorPagesMovieContext à página:The constructor uses dependency injection to add the RazorPagesMovieContext to the page:

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

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

Confira Código assíncrono para obter mais informações sobre a programação assíncrona com o Entity Framework.See Asynchronous code for more information on asynchronous programming with Entity Framework.

Quando uma solicitação é feita para a página, o OnGetAsync método retorna uma lista de filmes para a Razor página.When a request is made for the page, the OnGetAsync method returns a list of movies to the Razor Page. Em uma Razor página, OnGetAsync ou OnGet é chamado para inicializar o estado da página.On a Razor Page, OnGetAsync or OnGet is called to initialize the state of the page. Nesse caso, OnGetAsync obtém uma lista de filmes e os exibe.In this case, OnGetAsync gets a list of movies and displays them.

Quando OnGet retorna void ou OnGetAsync retorna Task , nenhuma instrução de retorno é usada.When OnGet returns void or OnGetAsync returns Task, no return statement is used. Por exemplo, a página de privacidade:For example the Privacy Page:

public class PrivacyModel : PageModel
{
    private readonly ILogger<PrivacyModel> _logger;

    public PrivacyModel(ILogger<PrivacyModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
    }
}

Quando o tipo de retorno for IActionResult ou Task<IActionResult>, é necessário fornecer uma instrução de retorno.When the return type is IActionResult or Task<IActionResult>, a return statement must be provided. Por exemplo, o método pages/Movies/Create. cshtml. cs OnPostAsync :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 a página páginas/filmes/ Index . cshtml Razor :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 pode fazer a transição de HTML para C# ou para uma Razor marcação específica.Razor can transition from HTML into C# or into Razor-specific markup. Quando um @ símbolo é seguido por uma Razor palavra-chave reservada, ele faz a transição para uma Razor marcação específica, caso contrário, ele faz a transição para o C#.When an @ symbol is followed by a Razor reserved keyword, it transitions into Razor-specific markup, otherwise it transitions into C#.

A diretiva @pageThe @page directive

A @page Razor diretiva torna o arquivo uma ação MVC, o que significa que ele pode lidar com solicitações.The @page Razor directive makes the file an MVC action, which means that it can handle requests. @page deve ser a primeira Razor diretiva em uma página.@page must be the first Razor directive on a page. @page e @model são exemplos de transição para Razor marcação específica.@page and @model are examples of transitioning into Razor-specific markup. Consulte a Razor sintaxe para obter mais informações.See Razor syntax for more information.

A diretiva @modelThe @model directive

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

A @model diretiva especifica o tipo do modelo passado para a Razor página.The @model directive specifies the type of the model passed to the Razor Page. No exemplo anterior, a @model linha torna a PageModel classe derivada disponível para a Razor página.In the preceding example, the @model line makes the PageModel-derived class available to the Razor Page. O modelo é usado nos auxiliares HTML@Html.DisplayNameFor e @Html.DisplayFor na página.The model is used in the @Html.DisplayNameFor and @Html.DisplayFor HTML Helpers on the page.

Examine a expressão lambda usada no auxiliar HTML a seguir:Examine the lambda expression used in the following HTML Helper:

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

O auxiliar HTML DisplayNameExtensions.DisplayNameFor inspeciona a propriedade Title referenciada na expressão lambda para determinar o nome de exibição.The DisplayNameExtensions.DisplayNameFor HTML Helper inspects the Title property referenced in the lambda expression to determine the display name. A expressão lambda é inspecionada em vez de avaliada.The lambda expression is inspected rather than evaluated. Isso significa que não há nenhuma violação de acesso quando model , model.Movie ou model.Movie[0] está null ou vazio.That means there is no access violation when model, model.Movie, or model.Movie[0] is null or empty. Quando a expressão lambda é avaliada, por exemplo, com @Html.DisplayFor(modelItem => item.Title) , os valores de Propriedade do modelo são avaliados.When the lambda expression is evaluated, for example, with @Html.DisplayFor(modelItem => item.Title), the model's property values are evaluated.

A página de layoutThe layout page

Selecione os links de menu Razor PagesMovie, Home e Privacy.Select the menu links RazorPagesMovie, Home, and Privacy. Cada página mostra o mesmo layout de menu.Each page shows the same menu layout. O layout de menu é implementado no arquivo Pages/Shared/_Layout.cshtml.The menu layout is implemented in the Pages/Shared/_Layout.cshtml file.

Abra e examine o arquivo pages/Shared/_Layout. cshtml .Open and examine the Pages/Shared/_Layout.cshtml file.

Os modelos de layout permitem que o layout do contêiner HTML seja:Layout templates allow the HTML container layout to be:

  • Especificado em um único lugar.Specified in one place.
  • Aplicado a várias páginas no site.Applied in multiple pages in the site.

Localize a linha @RenderBody().Find the @RenderBody() line. RenderBody é um espaço reservado em que todas as exibições específicas da página são mostradas, encapsuladas na página de layout.RenderBody is a placeholder where all the page-specific views show up, wrapped in the layout page. Por exemplo, selecione o link Privacidade e a exibição Pages/Privacy.cshtml será renderizada dentro do método RenderBody.For example, select the Privacy link and the Pages/Privacy.cshtml view is rendered inside the RenderBody method.

ViewData e layoutViewData and layout

Considere a seguinte marcação do arquivo pages/Movies/ Index . cshtml :Consider the following markup from the Pages/Movies/Index.cshtml file:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

A marcação realçada anterior é um exemplo de Razor transição para C#.The preceding highlighted markup is an example of Razor transitioning into C#. Os caracteres { e } circunscrevem um bloco de código C#.The { and } characters enclose a block of C# code.

A PageModel classe base contém uma ViewData Propriedade Dictionary que pode ser usada para passar dados para uma exibição.The PageModel base class contains a ViewData dictionary property that can be used to pass data to a View. Os objetos são adicionados ao ViewData dicionário usando um padrão de valor de chave .Objects are added to the ViewData dictionary using a key value pattern. No exemplo anterior, a propriedade Title é adicionada ao dicionário ViewData.In the preceding sample, the Title property is added to the ViewData dictionary.

A propriedade Title é usada no arquivo Pages/Shared/_Layout.cshtml.The Title property is used in the Pages/Shared/_Layout.cshtml file. A marcação a seguir mostra as primeiras linhas do arquivo Pages/_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.*@

A linha @*Markup removed for brevity.*@ é um Razor comentário.The line @*Markup removed for brevity.*@ is a Razor comment. Ao contrário dos comentários HTML <!-- --> , Razor os comentários não são enviados ao cliente.Unlike HTML comments <!-- -->, Razor comments are not sent to the client. Consulte MDN Web docs: introdução ao HTML para obter mais informações.See MDN web docs: Getting started with HTML for more information.

Atualizar o layoutUpdate the layout

  1. Altere o <title> elemento no arquivo pages/Shared/_Layout. cshtml para exibir o filme em vez de Razor PagesMovie.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>
    
  2. Localizar o elemento de âncora a seguir no arquivo 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>
    
  3. Substitua o elemento anterior pela marcação a seguir:Replace the preceding element with the following markup:

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

    O elemento de âncora anterior é um Auxiliar de Marcas.The preceding anchor element is a Tag Helper. Nesse caso, ele é o Auxiliar de Marcas de Âncora.In this case, it's the Anchor Tag Helper. O asp-page="/Movies/Index" atributo e o valor da marca auxiliar cria um link para a /Movies/Index Razor página.The asp-page="/Movies/Index" Tag Helper attribute and value creates a link to the /Movies/Index Razor Page. O valor do atributo asp-area está vazio e, portanto, a área não é usada no link.The asp-area attribute value is empty, so the area isn't used in the link. Confira Áreas para obter mais informações.See Areas for more information.

  4. Salve as alterações e teste o aplicativo selecionando o link RpMovie .Save the changes and test the app by selecting the RpMovie link. Confira o arquivo _Layout.cshtml no GitHub caso tenha problemas.See the _Layout.cshtml file in GitHub if you have any problems.

  5. Teste os links início, RpMovie, criar, Editar e excluir .Test the Home, RpMovie, Create, Edit, and Delete links. Cada página define o título, que você pode ver na guia navegador. Quando você marcar uma página, o título será usado para o indicador.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.

Observação

Talvez você não consiga inserir casas decimais ou vírgulas no campo Price.You may not be able to enter decimal commas in the Price field. Para dar suporte à validação do jQuery para localidades não inglesas que usam uma vírgula (",") para um ponto decimal e não US-English formatos de data, você deve executar etapas para globalizar o aplicativo.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 the app. Confira Problema 4076 do GitHub para obter instruções sobre como adicionar casas decimais.See this GitHub issue 4076 for instructions on adding decimal comma.

A propriedade Layout é definida no arquivo Pages/_ViewStart.cshtml:The Layout property is set in the Pages/_ViewStart.cshtml file:

@{
    Layout = "_Layout";
}

A marcação anterior define o arquivo de layout para pages/Shared/_Layout. cshtml para todos os Razor arquivos na pasta pages .The preceding markup sets the layout file to Pages/Shared/_Layout.cshtml for all Razor files under the Pages folder. Veja Layout para obter mais informações.See Layout for more information.

O modelo Criar páginaThe Create page model

Examine o 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");
        }
    }
}

O método OnGet inicializa qualquer estado necessário para a página.The OnGet method initializes any state needed for the page. A página Criar não tem nenhum estado para inicializar, assim, Page é retornado.The Create page doesn't have any state to initialize, so Page is returned. Apresentamos um exemplo de inicialização de estado OnGet posteriormente no tutorial.Later in the tutorial, an example of OnGet initializing state is shown. O método Page cria um objeto PageResult que renderiza a página Create.cshtml.The Page method creates a PageResult object that renders the Create.cshtml page.

A Movie propriedade usa o atributo [BindProperty] para aceitar a associação de modelo.The Movie property uses the [BindProperty] attribute to opt-in to model binding. Quando o formulário Criar posta os valores de formulário, o runtime do ASP.NET Core associa os valores postados ao modelo Movie.When the Create form posts the form values, the ASP.NET Core runtime binds the posted values to the Movie model.

O método OnPostAsync é executado quando a página posta dados de formulário: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");
}

Se há algum erro de modelo, o formulário é reexibido juntamente com quaisquer dados de formulário postados.If there are any model errors, the form is redisplayed, along with any form data posted. A maioria dos erros de modelo podem ser capturados no lado do cliente antes do formulário ser enviado.Most model errors can be caught on the client-side before the form is posted. Um exemplo de um erro de modelo é postar, para o campo de data, um valor que não pode ser convertido em uma data.An example of a model error is posting a value for the date field that cannot be converted to a date. A validação do lado do cliente e a validação de modelo são abordadas mais adiante no tutorial.Client-side validation and model validation are discussed later in the tutorial.

Se não houver nenhum erro de modelo:If there are no model errors:

  • Os dados são salvos.The data is saved.
  • O navegador é redirecionado para a Index página.The browser is redirected to the Index page.

A Razor página criarThe Create Razor Page

Examine o arquivo de página páginas/filmes/Create. cshtml Razor :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");}
}

O Visual Studio exibe as marcas a seguir em uma fonte em negrito diferente usada em auxiliares de marcações: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>

Exibição de VS17 da página Create.cshtml

O elemento <form method="post"> é um auxiliar de marcas de formulário.The <form method="post"> element is a Form Tag Helper. O auxiliar de marcas de formulário inclui automaticamente um token antifalsificação.The Form Tag Helper automatically includes an antiforgery token.

O mecanismo scaffolding cria a Razor marcação para cada campo no modelo, exceto o ID, semelhante ao seguinte: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>

Os auxiliares de marca de validação ( <div asp-validation-summary e <span asp-validation-for ) exibem erros de validação.The Validation Tag Helpers (<div asp-validation-summary and <span asp-validation-for) display validation errors. A validação será abordada em mais detalhes posteriormente nesta série.Validation is covered in more detail later in this series.

A marca de rótulo Helper ( <label asp-for="Movie.Title" class="control-label"></label> ) gera a legenda do rótulo e o [for] atributo para a Title propriedade.The Label Tag Helper (<label asp-for="Movie.Title" class="control-label"></label>) generates the label caption and [for] attribute for the Title property.

O auxiliar de marca de entrada ( <input asp-for="Movie.Title" class="form-control"> ) usa os atributos Annotations e produz atributos HTML necessários para a validação do jQuery no lado do 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 obter mais informações sobre Auxiliares de Marcas, como <form method="post">, confira Auxiliares de Marcas no ASP.NET Core.For more information on Tag Helpers such as <form method="post">, see Tag Helpers in ASP.NET Core.

Recursos adicionaisAdditional resources

As páginas Create, Delete, Details e EditThe Create, Delete, Details, and Edit pages

Examine o modelo de página páginas/filmes/ 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();
        }
    }
}

Razor As páginas são derivadas de PageModel .Razor Pages are derived from PageModel. Por convenção, a PageModel classe derivada é nomeada <PageName>Model .By convention, the PageModel-derived class is named <PageName>Model. O construtor usa injeção de dependência para adicionar o RazorPagesMovieContext à página.The constructor uses dependency injection to add the RazorPagesMovieContext to the page. As páginas com Scaffold seguem esse padrão.The scaffolded pages follow this pattern. Confira Código assíncrono para obter mais informações sobre a programação assíncrona com o Entity Framework.See Asynchronous code for more information on asynchronous programming with Entity Framework.

Quando uma solicitação é feita para a página, o OnGetAsync método retorna uma lista de filmes para a Razor página.When a request is made for the page, the OnGetAsync method returns a list of movies to the Razor Page. OnGetAsync ou OnGet é chamado em uma Razor página para inicializar o estado da página.OnGetAsync or OnGet is called on a Razor Page to initialize the state for the page. Nesse caso, OnGetAsync obtém uma lista de filmes e os exibe.In this case, OnGetAsync gets a list of movies and displays them.

Quando OnGet retorna void ou OnGetAsync retorna Task , nenhum método de retorno é usado.When OnGet returns void or OnGetAsync returns Task, no return method is used. Quando o tipo de retorno for IActionResult ou Task<IActionResult>, é necessário fornecer uma instrução de retorno.When the return type is IActionResult or Task<IActionResult>, a return statement must be provided. Por exemplo, o método pages/Movies/Create. cshtml. cs OnPostAsync :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 a página páginas/filmes/ Index . cshtml Razor :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 pode fazer a transição de HTML para C# ou para uma Razor marcação específica.Razor can transition from HTML into C# or into Razor-specific markup. Quando um @ símbolo é seguido por uma Razor palavra-chave reservada, ele faz a transição para uma Razor marcação específica, caso contrário, ele faz a transição para o C#.When an @ symbol is followed by a Razor reserved keyword, it transitions into Razor-specific markup, otherwise it transitions into C#.

A @page Razor diretiva transforma o arquivo em uma ação MVC, o que significa que ele pode lidar com solicitações.The @page Razor directive makes the file into an MVC action, which means that it can handle requests. @page deve ser a primeira Razor diretiva em uma página.@page must be the first Razor directive on a page. @page é um exemplo de transição para Razor marcação específica.@page is an example of transitioning into Razor-specific markup. Consulte a Razor sintaxe para obter mais informações.See Razor syntax for more information.

A diretiva @modelThe @model directive

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

A @model diretiva especifica o tipo do modelo passado para a Razor página.The @model directive specifies the type of the model passed to the Razor Page. No exemplo anterior, a @model linha torna a PageModel classe derivada disponível para a Razor página.In the preceding example, the @model line makes the PageModel-derived class available to the Razor Page. O modelo é usado nos auxiliares HTML@Html.DisplayNameFor e @Html.DisplayFor na página.The model is used in the @Html.DisplayNameFor and @Html.DisplayFor HTML Helpers on the page.

Auxiliares HTMLHTML Helpers

Examine a expressão lambda usada no auxiliar HTML a seguir:Examine the lambda expression used in the following HTML Helper:

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

O auxiliar HTML DisplayNameExtensions.DisplayNameFor inspeciona a propriedade Title referenciada na expressão lambda para determinar o nome de exibição.The DisplayNameExtensions.DisplayNameFor HTML Helper inspects the Title property referenced in the lambda expression to determine the display name. A expressão lambda é inspecionada em vez de avaliada.The lambda expression is inspected rather than evaluated. Isso significa que não há nenhuma violação de acesso quando model, model.Movie ou model.Movie[0] são null ou vazios.That means there is no access violation when model, model.Movie, or model.Movie[0] are null or empty. Quando a expressão lambda é avaliada, por exemplo, com @Html.DisplayFor(modelItem => item.Title) , os valores de Propriedade do modelo são avaliados.When the lambda expression is evaluated, for example, with @Html.DisplayFor(modelItem => item.Title), the model's property values are evaluated.

A página de layoutThe layout page

Selecione os links de menu Razor PagesMovie, Home e Privacy.Select the menu links RazorPagesMovie, Home, and Privacy. Cada página mostra o mesmo layout de menu.Each page shows the same menu layout. O layout de menu é implementado no arquivo Pages/Shared/_Layout.cshtml.The menu layout is implemented in the Pages/Shared/_Layout.cshtml file.

Abra e examine o arquivo pages/Shared/_Layout. cshtml .Open and examine the Pages/Shared/_Layout.cshtml file.

Os modelos de layout permitem especificar o layout de contêiner HTML de um site em um único local e, em seguida, aplicá-lo em várias páginas no site.Layout templates allow you to specify the HTML container layout of a site in one place and then apply it across multiple pages in the site. Localize a linha @RenderBody().Find the @RenderBody() line. RenderBody é um espaço reservado em que todas as visualizações específicas da página criadas são mostradas, encapsuladas na página de layout.RenderBody is a placeholder where all the page-specific views you create show up, wrapped in the layout page. Por exemplo, se você selecionar o link Privacidade, a exibição Pages/Privacy.cshtml será renderizada dentro do método RenderBody.For example, if you select the Privacy link, the Pages/Privacy.cshtml view is rendered inside the RenderBody method.

ViewData e layoutViewData and layout

Considere o seguinte código do arquivo pages/Movies/ Index . cshtml :Consider the following code from the Pages/Movies/Index.cshtml file:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

O código realçado anterior é um exemplo de Razor transição para o C#.The preceding highlighted code is an example of Razor transitioning into C#. Os caracteres { e } circunscrevem um bloco de código C#.The { and } characters enclose a block of C# code.

A classe base PageModel tem uma propriedade de dicionário ViewData que pode ser usada para adicionar os dados que você deseja passar para uma exibição.The PageModel base class has a ViewData dictionary property that can be used to add data that you want to pass to a View. Você adiciona objetos ao dicionário ViewData usando um padrão de chave/valor.You add objects into the ViewData dictionary using a key/value pattern. No exemplo anterior, a propriedade Title é adicionada ao dicionário ViewData.In the preceding sample, the Title property is added to the ViewData dictionary.

A propriedade Title é usada no arquivo Pages/Shared/_Layout.cshtml.The Title property is used in the Pages/Shared/_Layout.cshtml file. A marcação a seguir mostra as primeiras linhas do arquivo Pages/_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.*@

A linha @*Markup removed for brevity.*@ é um Razor comentário.The line @*Markup removed for brevity.*@ is a Razor comment. Ao contrário dos comentários HTML <!-- --> , Razor os comentários não são enviados ao cliente.Unlike HTML comments <!-- -->, Razor comments are not sent to the client. Consulte MDN Web docs: introdução ao HTML para obter mais informações.See MDN web docs: Getting started with HTML for more information.

Atualizar o layoutUpdate the layout

Altere o <title> elemento no arquivo pages/Shared/_Layout. cshtml para exibir o filme em vez de Razor PagesMovie.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>

Localizar o elemento de âncora a seguir no arquivo 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>

Substitua o elemento anterior pela marcação a seguir.Replace the preceding element with the following markup.

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

O elemento de âncora anterior é um Auxiliar de Marcas.The preceding anchor element is a Tag Helper. Nesse caso, ele é o Auxiliar de Marcas de Âncora.In this case, it's the Anchor Tag Helper. O asp-page="/Movies/Index" atributo e o valor da marca auxiliar cria um link para a /Movies/Index Razor página.The asp-page="/Movies/Index" Tag Helper attribute and value creates a link to the /Movies/Index Razor Page. O valor do atributo asp-area está vazio e, portanto, a área não é usada no link.The asp-area attribute value is empty, so the area isn't used in the link. Confira Áreas para obter mais informações.See Areas for more information.

Salve suas alterações e teste o aplicativo clicando no link RpMovie.Save your changes, and test the app by clicking on the RpMovie link. Confira o arquivo _Layout.cshtml no GitHub caso tenha problemas.See the _Layout.cshtml file in GitHub if you have any problems.

Teste os outros links (Home, RpMovie, Create, Edit e Delete).Test the other links (Home, RpMovie, Create, Edit, and Delete). Cada página define o título, que você pode ver na guia navegador. Quando você marcar uma página, o título será usado para o indicador.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.

Observação

Talvez você não consiga inserir casas decimais ou vírgulas no campo Price.You may not be able to enter decimal commas in the Price field. Para dar suporte à validação do jQuery para localidades não inglesas que usam uma vírgula (",") para um ponto decimal e não US-English formatos de data, você deve executar etapas para globalizar o aplicativo.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 the app. Veja Problema 4076 do GitHub para obter instruções sobre como adicionar casas decimais.This GitHub issue 4076 for instructions on adding decimal comma.

A propriedade Layout é definida no arquivo Pages/_ViewStart.cshtml:The Layout property is set in the Pages/_ViewStart.cshtml file:

@{
    Layout = "_Layout";
}

A marcação anterior define o arquivo de layout para pages/Shared/_Layout. cshtml para todos os Razor arquivos na pasta pages .The preceding markup sets the layout file to Pages/Shared/_Layout.cshtml for all Razor files under the Pages folder. Veja Layout para obter mais informações.See Layout for more information.

O modelo Criar páginaThe Create page model

Examine o 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");
        }
    }
}

O método OnGet inicializa qualquer estado necessário para a página.The OnGet method initializes any state needed for the page. A página Criar não tem nenhum estado para inicializar, assim, Page é retornado.The Create page doesn't have any state to initialize, so Page is returned. Mais adiante no tutorial, você verá o estado de inicialização do método OnGet.Later in the tutorial you see OnGet method initialize state. O método Page cria um objeto PageResult que renderiza a página Create.cshtml.The Page method creates a PageResult object that renders the Create.cshtml page.

A Movie propriedade usa o atributo [[BindProperty]] BindPropertyAttribute para aceitar a associação de modelo.The Movie property uses the [[BindProperty]]BindPropertyAttribute attribute to opt-in to model binding. Quando o formulário Criar posta os valores de formulário, o runtime do ASP.NET Core associa os valores postados ao modelo Movie.When the Create form posts the form values, the ASP.NET Core runtime binds the posted values to the Movie model.

O método OnPostAsync é executado quando a página posta dados de formulário: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");
}

Se há algum erro de modelo, o formulário é reexibido juntamente com quaisquer dados de formulário postados.If there are any model errors, the form is redisplayed, along with any form data posted. A maioria dos erros de modelo podem ser capturados no lado do cliente antes do formulário ser enviado.Most model errors can be caught on the client-side before the form is posted. Um exemplo de um erro de modelo é postar, para o campo de data, um valor que não pode ser convertido em uma data.An example of a model error is posting a value for the date field that cannot be converted to a date. A validação do lado do cliente e a validação de modelo são abordadas mais adiante no tutorial.Client-side validation and model validation are discussed later in the tutorial.

Se não houver nenhum erro de modelo, os dados serão salvos e o navegador será redirecionado para a Index página.If there are no model errors, the data is saved, and the browser is redirected to the Index page.

A Razor página criarThe Create Razor Page

Examine o arquivo de página páginas/filmes/Create. cshtml Razor :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");}
}

O Visual Studio exibe a marca <form method="post"> em uma fonte em negrito diferente usada para Auxiliares de Marcas:Visual Studio displays the <form method="post"> tag in a distinctive bold font used for Tag Helpers:

Exibição de VS17 da página Create.cshtml

O elemento <form method="post"> é um auxiliar de marcas de formulário.The <form method="post"> element is a Form Tag Helper. O auxiliar de marcas de formulário inclui automaticamente um token antifalsificação.The Form Tag Helper automatically includes an antiforgery token.

O mecanismo scaffolding cria a Razor marcação para cada campo no modelo, exceto o ID, semelhante ao seguinte: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>

Os auxiliares de marca de validação ( <div asp-validation-summary e <span asp-validation-for ) exibem erros de validação.The Validation Tag Helpers (<div asp-validation-summary and <span asp-validation-for) display validation errors. A validação será abordada em mais detalhes posteriormente nesta série.Validation is covered in more detail later in this series.

A marca de rótulo Helper ( <label asp-for="Movie.Title" class="control-label"></label> ) gera a legenda do rótulo e o [for] atributo para a Title propriedade.The Label Tag Helper (<label asp-for="Movie.Title" class="control-label"></label>) generates the label caption and [for] attribute for the Title property.

O auxiliar de marca de entrada ( <input asp-for="Movie.Title" class="form-control"> ) usa os atributos Annotations e produz atributos HTML necessários para a validação do jQuery no lado do 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 adicionaisAdditional resources