Introdução a Páginas do Razor no ASP.NET CoreIntroduction to Razor Pages in ASP.NET Core

Por Rick Anderson e Ryan NowakBy Rick Anderson and Ryan Nowak

Páginas do Razor é um novo aspecto do ASP.NET Core MVC que torna a codificação de cenários focados em página mais fácil e produtiva.Razor Pages is a new aspect of ASP.NET Core MVC that makes coding page-focused scenarios easier and more productive.

Se você estiver procurando um tutorial que utiliza a abordagem Modelo-Exibição-Controlador, consulte a Introdução ao ASP.NET Core MVC.If you're looking for a tutorial that uses the Model-View-Controller approach, see Get started with ASP.NET Core MVC.

Este documento proporciona uma introdução a páginas do Razor.This document provides an introduction to Razor Pages. Este não é um tutorial passo a passo.It's not a step by step tutorial. Se você achar que algumas das seções são muito avançadas, consulte a Introdução a Páginas do Razor.If you find some of the sections too advanced, see Get started with Razor Pages. Para obter uma visão geral do ASP.NET Core, consulte a Introdução ao ASP.NET Core.For an overview of ASP.NET Core, see the Introduction to ASP.NET Core.

Pré-requisitosPrerequisites

Pré-requisitosPrerequisites

Criar um projeto do Razor PagesCreate a Razor Pages project

Confira a Introdução ao Razor Pages para obter instruções detalhadas sobre como criar um projeto do Razor Pages.See Get started with Razor Pages for detailed instructions on how to create a Razor Pages project.

Páginas do RazorRazor Pages

O Páginas do Razor está habilitado em Startup.cs:Razor Pages is enabled in Startup.cs:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Includes support for Razor Pages and controllers.
        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc();
    }
}

Considere uma página básica: Consider a basic page:

@page

<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>

O código anterior se assemelha muito a um arquivo de exibição do Razor usado em um aplicativo ASP.NET Core com controladores e exibições.The preceding code looks a lot like a Razor view file used in an ASP.NET Core app with controllers and views. O que o torna diferentes é a diretiva @page.What makes it different is the @page directive. @page transforma o arquivo em uma ação do MVC – o que significa que ele trata solicitações diretamente, sem passar por um controlador.@page makes the file into an MVC action - which means that it handles requests directly, without going through a controller. @page deve ser a primeira diretiva do Razor em uma página.@page must be the first Razor directive on a page. @page afeta o comportamento de outros constructos do Razor.@page affects the behavior of other Razor constructs.

Uma página semelhante, usando uma classe PageModel, é mostrada nos dois arquivos a seguir.A similar page, using a PageModel class, is shown in the following two files. O arquivo Pages/Index2.cshtml:The Pages/Index2.cshtml file:

@page
@using RazorPagesIntro.Pages
@model IndexModel2

<h2>Separate page model</h2>
<p>
    @Model.Message
</p>

O modelo de página Pages/Index2.cshtml.cs:The Pages/Index2.cshtml.cs page model:

using Microsoft.AspNetCore.Mvc.RazorPages;
using System;

namespace RazorPagesIntro.Pages
{
    public class IndexModel2 : PageModel
    {
        public string Message { get; private set; } = "PageModel in C#";

        public void OnGet()
        {
            Message += $" Server time is { DateTime.Now }";
        }
    }
}

Por convenção, o arquivo de classe PageModel tem o mesmo nome que o arquivo na Página do Razor com .cs acrescentado.By convention, the PageModel class file has the same name as the Razor Page file with .cs appended. Por exemplo, a Página do Razor anterior é Pages/Index2.cshtml.For example, the previous Razor Page is Pages/Index2.cshtml. O arquivo que contém a classe PageModel é chamado Pages/Index2.cshtml.cs.The file containing the PageModel class is named Pages/Index2.cshtml.cs.

As associações de caminhos de URL para páginas são determinadas pelo local da página no sistema de arquivos.The associations of URL paths to pages are determined by the page's location in the file system. A tabela a seguir mostra um caminho de Página do Razor e a URL correspondente:The following table shows a Razor Page path and the matching URL:

Caminho e nome do arquivoFile name and path URL correspondentematching URL
/Pages/Index.cshtml/Pages/Index.cshtml / ou /Index/ or /Index
/Pages/Contact.cshtml/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml/Pages/Store/Index.cshtml /Store ou /Store/Index/Store or /Store/Index

Notas:Notes:

  • O tempo de execução procura arquivos de Páginas do Razor na pasta Pages por padrão.The runtime looks for Razor Pages files in the Pages folder by default.
  • Index é a página padrão quando uma URL não inclui uma página.Index is the default page when a URL doesn't include a page.

Escrever um formulário básicoWrite a basic form

Páginas do Razor foi projetado para facilitar a implementação de padrões comuns usados com navegadores da Web ao criar um aplicativo.Razor Pages is designed to make common patterns used with web browsers easy to implement when building an app. Model binding, auxiliares de marcas e auxiliares HTML funcionam todos apenas com as propriedades definidas em uma classe de Página do Razor.Model binding, Tag Helpers, and HTML helpers all just work with the properties defined in a Razor Page class. Considere uma página que implementa um formulário básico "Fale conosco" para o modelo Contact:Consider a page that implements a basic "contact us" form for the Contact model:

Para as amostras neste documento, o DbContext é inicializado no arquivo Startup.cs.For the samples in this document, the DbContext is initialized in the Startup.cs file.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorPagesContacts.Data;

namespace RazorPagesContacts
{
    public class Startup
    {
        public IHostingEnvironment HostingEnvironment { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>(options =>
                              options.UseInMemoryDatabase("name"));
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseMvc();
        }
    }
}

O modelo de dados:The data model:

using System.ComponentModel.DataAnnotations;

namespace RazorPagesContacts.Data
{
    public class Customer
    {
        public int Id { get; set; }

        [Required, StringLength(100)]
        public string Name { get; set; }
    }
}

O contexto do banco de dados:The db context:

using Microsoft.EntityFrameworkCore;

namespace RazorPagesContacts.Data
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions options)
            : base(options)
        {
        }

        public DbSet<Customer> Customers { get; set; }
    }
}

O arquivo de exibição Pages/Create.cshtml:The Pages/Create.cshtml view file:

@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>

O modelo de página Pages/Create.cshtml.cs:The Pages/Create.cshtml.cs page model:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages
{
    public class CreateModel : PageModel
    {
        private readonly AppDbContext _db;

        public CreateModel(AppDbContext db)
        {
            _db = db;
        }

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

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

            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();
            return RedirectToPage("/Index");
        }
    }
}

Por convenção, a classe PageModel é chamada de <PageName>Model e está no mesmo namespace que a página.By convention, the PageModel class is called <PageName>Model and is in the same namespace as the page.

A classe PageModel permite separar a lógica de uma página da respectiva apresentação.The PageModel class allows separation of the logic of a page from its presentation. Ela define manipuladores para as solicitações enviadas e os dados usados para renderizar a página.It defines page handlers for requests sent to the page and the data used to render the page. Esta separação permite gerenciar as dependências da página por meio de injeção de dependência e realizar um teste de unidade nas páginas.This separation allows you to manage page dependencies through dependency injection and to unit test the pages.

A página tem um método de manipulador OnPostAsync, que é executado em solicitações POST (quando um usuário posta o formulário).The page has an OnPostAsync handler method, which runs on POST requests (when a user posts the form). Você pode adicionar métodos de manipulador para qualquer verbo HTTP.You can add handler methods for any HTTP verb. Os manipuladores mais comuns são:The most common handlers are:

  • OnGet para inicializar o estado necessário para a página.OnGet to initialize state needed for the page. Amostra de OnGet.OnGet sample.
  • OnPost para manipular envios de formulário.OnPost to handle form submissions.

O sufixo de nomenclatura Async é opcional, mas geralmente é usado por convenção para funções assíncronas.The Async naming suffix is optional but is often used by convention for asynchronous functions. O código OnPostAsync no exemplo anterior tem aparência semelhante ao que você normalmente escreve em um controlador.The OnPostAsync code in the preceding example looks similar to what you would normally write in a controller. O código anterior é comum para as Páginas do Razor.The preceding code is typical for Razor Pages. A maioria dos primitivos MVC como model binding, validação e resultados da ação são compartilhados.Most of the MVC primitives like model binding, validation, and action results are shared.

O método OnPostAsync anterior:The previous OnPostAsync method:

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

    _db.Customers.Add(Customer);
    await _db.SaveChangesAsync();
    return RedirectToPage("/Index");
}

O fluxo básico de OnPostAsync:The basic flow of OnPostAsync:

Verifique se há erros de validação.Check for validation errors.

  • Se não houver nenhum erro, salve os dados e redirecione.If there are no errors, save the data and redirect.
  • Se houver erros, mostre a página novamente com as mensagens de validação.If there are errors, show the page again with validation messages. A validação do lado do cliente é idêntica para aplicativos ASP.NET Core MVC tradicionais.Client-side validation is identical to traditional ASP.NET Core MVC applications. Em muitos casos, erros de validação seriam detectados no cliente e nunca enviados ao servidor.In many cases, validation errors would be detected on the client, and never submitted to the server.

Quando os dados são inseridos com êxito, o método de manipulador OnPostAsync chama o método auxiliar RedirectToPage para retornar uma instância de RedirectToPageResult.When the data is entered successfully, the OnPostAsync handler method calls the RedirectToPage helper method to return an instance of RedirectToPageResult. RedirectToPage é um novo resultado de ação, semelhante a RedirectToAction ou RedirectToRoute, mas personalizado para páginas.RedirectToPage is a new action result, similar to RedirectToAction or RedirectToRoute, but customized for pages. Na amostra anterior, ele redireciona para a página de Índice raiz (/Index).In the preceding sample, it redirects to the root Index page (/Index). RedirectToPage é descrito em detalhes na seção Geração de URLs para páginas.RedirectToPage is detailed in the URL generation for Pages section.

Quando o formulário enviado tem erros de validação (que são passados para o servidor), o método de manipulador OnPostAsync chama o método auxiliar Page.When the submitted form has validation errors (that are passed to the server), theOnPostAsync handler method calls the Page helper method. Page retorna uma instância de PageResult.Page returns an instance of PageResult. Retornar Page é semelhante a como as ações em controladores retornam View.Returning Page is similar to how actions in controllers return View. PageResult é o tipoPageResult is the default de retorno padrão para um método de manipulação.return type for a handler method. Um método de manipulador que retorna void renderiza a página.A handler method that returns void renders the page.

A propriedade Customer usa o atributo [BindProperty] para aceitar o model binding.The Customer property uses [BindProperty] attribute to opt in to model binding.

public class CreateModel : PageModel
{
    private readonly AppDbContext _db;

    public CreateModel(AppDbContext db)
    {
        _db = db;
    }

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

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

        _db.Customers.Add(Customer);
        await _db.SaveChangesAsync();
        return RedirectToPage("/Index");
    }
}

Páginas do Razor, por padrão, associam as propriedades somente com verbos não GET.Razor Pages, by default, bind properties only with non-GET verbs. A associação de propriedades pode reduzir a quantidade de código que você precisa escrever.Binding to properties can reduce the amount of code you have to write. A associação reduz o código usando a mesma propriedade para renderizar os campos de formulário (<input asp-for="Customer.Name">) e aceitar a entrada.Binding reduces code by using the same property to render form fields (<input asp-for="Customer.Name">) and accept the input.

Aviso

Por motivos de segurança, você deve aceitar associar os dados da solicitação GET às propriedades do modelo de página.For security reasons, you must opt in to binding GET request data to page model properties. Verifique a entrada do usuário antes de mapeá-la para as propriedades.Verify user input before mapping it to properties. Aceitar a associação de GET é útil ao lidar com cenários que contam com a cadeia de caracteres de consulta ou com os valores de rota.Opting in to GET binding is useful when addressing scenarios which rely on query string or route values.

Para associar uma propriedade às solicitações GET, defina a propriedade SupportsGet do atributo [BindProperty] como true: [BindProperty(SupportsGet = true)]To bind a property on GET requests, set the [BindProperty] attribute's SupportsGet property to true: [BindProperty(SupportsGet = true)]

A home page (Index.cshtml):The home page (Index.cshtml):

@page
@model RazorPagesContacts.Pages.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<h1>Contacts</h1>
<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var contact in Model.Customers)
            {
                <tr>
                    <td>@contact.Id</td>
                    <td>@contact.Name</td>
                    <td>
                        <a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>
                        <button type="submit" asp-page-handler="delete" 
                                asp-route-id="@contact.Id">delete</button>
                    </td>
                </tr>
            }
        </tbody>
    </table>

    <a asp-page="./Create">Create</a>
</form>

A classe PageModel (Index.cshtml.cs) associada:The associated PageModel class (Index.cshtml.cs):

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;

namespace RazorPagesContacts.Pages
{
    public class IndexModel : PageModel
    {
        private readonly AppDbContext _db;

        public IndexModel(AppDbContext db)
        {
            _db = db;
        }

        public IList<Customer> Customers { get; private set; }

        public async Task OnGetAsync()
        {
            Customers = await _db.Customers.AsNoTracking().ToListAsync();
        }

        public async Task<IActionResult> OnPostDeleteAsync(int id)
        {
            var contact = await _db.Customers.FindAsync(id);

            if (contact != null)
            {
                _db.Customers.Remove(contact);
                await _db.SaveChangesAsync();
            }

            return RedirectToPage();
        }
    }
}

O arquivo cshtml contém a marcação a seguir para criar um link de edição para cada contato:The Index.cshtml file contains the following markup to create an edit link for each contact:

<a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>

O auxiliar de marcas de âncora usou o atributo asp-route-{value} para gerar um link para a página Edit.The Anchor Tag Helper used the asp-route-{value} attribute to generate a link to the Edit page. O link contém dados de rota com a ID de contato.The link contains route data with the contact ID. Por exemplo, http://localhost:5000/Edit/1.For example, http://localhost:5000/Edit/1. Use o atributo asp-area para especificar uma área.Use the asp-area attribute to specify an area. Para obter mais informações, consulte Áreas no ASP.NET Core.For more information, see Áreas no ASP.NET Core.

O arquivo Pages/Edit.cshtml:The Pages/Edit.cshtml file:

@page "{id:int}"
@model RazorPagesContacts.Pages.EditModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@{
    ViewData["Title"] = "Edit Customer";
}

<h1>Edit Customer - @Model.Customer.Id</h1>
<form method="post">
    <div asp-validation-summary="All"></div>
    <input asp-for="Customer.Id" type="hidden" />
    <div>
        <label asp-for="Customer.Name"></label>
        <div>
            <input asp-for="Customer.Name" />
            <span asp-validation-for="Customer.Name" ></span>
        </div>
    </div>
 
    <div>
        <button type="submit">Save</button>
    </div>
</form>

A primeira linha contém a diretiva @page "{id:int}".The first line contains the @page "{id:int}" directive. A restrição de roteamento "{id:int}" informa à página para aceitar solicitações para a página que contêm dados da rota int.The routing constraint"{id:int}" tells the page to accept requests to the page that contain int route data. Se uma solicitação para a página não contém dados de rota que podem ser convertidos em um int, o tempo de execução retorna um erro HTTP 404 (não encontrado).If a request to the page doesn't contain route data that can be converted to an int, the runtime returns an HTTP 404 (not found) error. Para tornar a ID opcional, acrescente ? à restrição de rota:To make the ID optional, append ? to the route constraint:

@page "{id:int?}"

O arquivo Pages/Edit.cshtml.cs:The Pages/Edit.cshtml.cs file:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages
{
    public class EditModel : PageModel
    {
        private readonly AppDbContext _db;

        public EditModel(AppDbContext db)
        {
            _db = db;
        }

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

        public async Task<IActionResult> OnGetAsync(int id)
        {
            Customer = await _db.Customers.FindAsync(id);

            if (Customer == null)
            {
                return RedirectToPage("/Index");
            }

            return Page();
        }

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

            _db.Attach(Customer).State = EntityState.Modified;

            try
            {
                await _db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                throw new Exception($"Customer {Customer.Id} not found!");
            }

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

O arquivo Index.cshtml também contém a marcação para criar um botão de exclusão para cada contato de cliente:The Index.cshtml file also contains markup to create a delete button for each customer contact:

<button type="submit" asp-page-handler="delete" 
        asp-route-id="@contact.Id">delete</button>

Quando o botão de exclusão é renderizado em HTML, seu formaction inclui parâmetros para:When the delete button is rendered in HTML, its formaction includes parameters for:

  • A ID de contato do cliente especificada pelo atributo asp-route-id.The customer contact ID specified by the asp-route-id attribute.
  • O handler especificado pelo atributo asp-page-handler.The handler specified by the asp-page-handler attribute.

Este é um exemplo de um botão de exclusão renderizado com uma ID de contato do cliente de 1:Here is an example of a rendered delete button with a customer contact ID of 1:

<button type="submit" formaction="/?id=1&amp;handler=delete">delete</button>

Quando o botão é selecionado, uma solicitação de formulário POST é enviada para o servidor.When the button is selected, a form POST request is sent to the server. Por convenção, o nome do método do manipulador é selecionado com base no valor do parâmetro handler de acordo com o esquema OnPost[handler]Async.By convention, the name of the handler method is selected based on the value of the handler parameter according to the scheme OnPost[handler]Async.

Como o handler é delete neste exemplo, o método do manipulador OnPostDeleteAsync é usado para processar a solicitação POST.Because the handler is delete in this example, the OnPostDeleteAsync handler method is used to process the POST request. Se o asp-page-handler for definido como um valor diferente, como remove, um método de manipulador de página com o nome OnPostRemoveAsync será selecionado.If the asp-page-handler is set to a different value, such as remove, a page handler method with the name OnPostRemoveAsync is selected.

public async Task<IActionResult> OnPostDeleteAsync(int id)
{
    var contact = await _db.Customers.FindAsync(id);

    if (contact != null)
    {
        _db.Customers.Remove(contact);
        await _db.SaveChangesAsync();
    }

    return RedirectToPage();
}

O método OnPostDeleteAsync:The OnPostDeleteAsync method:

  • Aceita o id da cadeia de caracteres de consulta.Accepts the id from the query string.
  • Consulta o banco de dados para o contato de cliente com FindAsync.Queries the database for the customer contact with FindAsync.
  • Se o contato do cliente for encontrado, eles serão removidos da lista de contatos do cliente.If the customer contact is found, they're removed from the list of customer contacts. O banco de dados é atualizado.The database is updated.
  • Chama RedirectToPage para redirecionar para a página de índice de raiz (/Index).Calls RedirectToPage to redirect to the root Index page (/Index).

Marque as propriedades da página conforme necessárioMark page properties as required

As propriedades em um PageModel podem ser decoradas com o atributo Required:Properties on a PageModel can be decorated with the Required attribute:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;

namespace RazorPagesMovie.Pages.Movies
{
    public class CreateModel : PageModel
    {
        public IActionResult OnGet()
        {
            return Page();
        }

        [BindProperty]
        [Required(ErrorMessage = "Color is required")]
        public string Color { get; set; }

        public IActionResult OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            // Process color.

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

Para obter mais informações, confira Validação de modelo.For more information, see Model validation.

Gerenciar solicitações HEAD com o manipulador OnGetManage HEAD requests with the OnGet handler

As solicitações HEAD permitem recuperar os cabeçalhos de um recurso específico.HEAD requests allow you to retrieve the headers for a specific resource. Ao contrário das solicitações GET, as solicitações HEAD não retornam um corpo de resposta.Unlike GET requests, HEAD requests don't return a response body.

Geralmente, um manipulador HEAD é criado e chamado para solicitações HEAD:Ordinarily, a HEAD handler is created and called for HEAD requests:

public void OnHead()
{
    HttpContext.Response.Headers.Add("HandledBy", "Handled by OnHead!");
}

Caso nenhum manipulador HEAD (OnHead) seja definido, as Páginas Razor voltam a chamar o manipulador de página GET (OnGet) no ASP.NET Core 2.1 ou posterior.If no HEAD handler (OnHead) is defined, Razor Pages falls back to calling the GET page handler (OnGet) in ASP.NET Core 2.1 or later. No ASP.NET Core 2.1 e 2.2, esse comportamento ocorre com o SetCompatibilityVersion em Startup.Configure:In ASP.NET Core 2.1 and 2.2, this behavior occurs with the SetCompatibilityVersion in Startup.Configure:

services.AddMvc()
    .SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1);

Os modelos padrão geram a chamada SetCompatibilityVersion no ASP.NET Core 2.1 e 2.2.The default templates generate the SetCompatibilityVersion call in ASP.NET Core 2.1 and 2.2.

SetCompatibilityVersion define de forma eficiente a opção de Páginas Razor AllowMappingHeadRequestsToGetHandler como true.SetCompatibilityVersion effectively sets the Razor Pages option AllowMappingHeadRequestsToGetHandler to true.

Em vez de aceitar todos os 2.1 comportamentos com SetCompatibilityVersion, você pode explicitamente participar de comportamentos específicos.Rather than opting into all 2.1 behaviors with SetCompatibilityVersion, you can explicitly opt-in to specific behaviors. O código a seguir aceita as solicitações de mapeamento HEAD para o manipulador GET.The following code opts into the mapping HEAD requests to the GET handler.

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        options.AllowMappingHeadRequestsToGetHandler = true;
    });

XSRF/CSRF e Páginas do RazorXSRF/CSRF and Razor Pages

Você não precisa escrever nenhum código para validação antifalsificação.You don't have to write any code for antiforgery validation. Validação e geração de token antifalsificação são automaticamente incluídas nas Páginas do Razor.Antiforgery token generation and validation are automatically included in Razor Pages.

Usando Layouts, parciais, modelos e auxiliares de marcas com Páginas do RazorUsing Layouts, partials, templates, and Tag Helpers with Razor Pages

As Páginas funcionam com todos os recursos do mecanismo de exibição do Razor.Pages work with all the capabilities of the Razor view engine. Layouts, parciais, modelos, auxiliares de marcas, _ViewStart.cshtml e _ViewImports.cshtml funcionam da mesma forma que funcionam exibições convencionais do Razor.Layouts, partials, templates, Tag Helpers, _ViewStart.cshtml, _ViewImports.cshtml work in the same way they do for conventional Razor views.

Organizaremos essa página aproveitando alguns desses recursos.Let's declutter this page by taking advantage of some of those capabilities.

Adicione uma página de layout a Pages/Shared/_Layout.cshtml:Add a layout page to Pages/Shared/_Layout.cshtml:

Adicione uma página de layout a Pages/_Layout.cshtml:Add a layout page to Pages/_Layout.cshtml:

<!DOCTYPE html>
<html>
<head> 
    <title>Razor Pages Sample</title>      
</head>
<body>    
   <a asp-page="/Index">Home</a>
    @RenderBody()  
    <a asp-page="/Customers/Create">Create</a> <br />
</body>
</html>

O Layout:The Layout:

  • Controla o layout de cada página (a menos que a página opte por não usar o layout).Controls the layout of each page (unless the page opts out of layout).
  • Importa estruturas HTML como JavaScript e folhas de estilo.Imports HTML structures such as JavaScript and stylesheets.

Veja página de layout para obter mais informações.See layout page for more information.

A propriedade Layout é definida em Pages/_ViewStart.cshtml:The Layout property is set in Pages/_ViewStart.cshtml:

@{
    Layout = "_Layout";
}

O layout está na pasta Pages/Shared.The layout is in the Pages/Shared folder. As páginas buscam outras exibições (layouts, modelos, parciais) hierarquicamente, iniciando na mesma pasta que a página atual.Pages look for other views (layouts, templates, partials) hierarchically, starting in the same folder as the current page. Um layout na pasta Pages/Shared pode ser usado em qualquer página do Razor na pasta Pages.A layout in the Pages/Shared folder can be used from any Razor page under the Pages folder.

O arquivo de layout deve entrar na pasta Pages/Shared.The layout file should go in the Pages/Shared folder.

O layout está na pasta Pages.The layout is in the Pages folder. As páginas buscam outras exibições (layouts, modelos, parciais) hierarquicamente, iniciando na mesma pasta que a página atual.Pages look for other views (layouts, templates, partials) hierarchically, starting in the same folder as the current page. Um layout na pasta Pages pode ser usado em qualquer Página do Razor na pasta Pages.A layout in the Pages folder can be used from any Razor page under the Pages folder.

Recomendamos que você não coloque o arquivo de layout na pasta Views/Shared.We recommend you not put the layout file in the Views/Shared folder. Views/Shared é um padrão de exibições do MVC.Views/Shared is an MVC views pattern. As Páginas do Razor devem confiar na hierarquia de pasta e não nas convenções de caminho.Razor Pages are meant to rely on folder hierarchy, not path conventions.

A pesquisa de modo de exibição de uma Página do Razor inclui a pasta Pages.View search from a Razor Page includes the Pages folder. Os layouts, modelos e parciais que você está usando com controladores MVC e exibições do Razor convencionais apenas funcionam.The layouts, templates, and partials you're using with MVC controllers and conventional Razor views just work.

Adicione um arquivo Pages/_ViewImports.cshtml:Add a Pages/_ViewImports.cshtml file:

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@namespace é explicado posteriormente no tutorial.@namespace is explained later in the tutorial. A diretiva @addTagHelper coloca os auxiliares de marcas internos em todas as páginas na pasta Pages.The @addTagHelper directive brings in the built-in Tag Helpers to all the pages in the Pages folder.

Quando a diretiva @namespace é usada explicitamente em uma página:When the @namespace directive is used explicitly on a page:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

<h2>Name space</h2>
<p>
    @Model.Message
</p>

A diretiva define o namespace da página.The directive sets the namespace for the page. A diretiva @model não precisa incluir o namespace.The @model directive doesn't need to include the namespace.

Quando a diretiva @namespace está contida em _ViewImports.cshtml, o namespace especificado fornece o prefixo do namespace gerado na página que importa a diretiva @namespace.When the @namespace directive is contained in _ViewImports.cshtml, the specified namespace supplies the prefix for the generated namespace in the Page that imports the @namespace directive. O restante do namespace gerado (a parte do sufixo) é o caminho relativo separado por ponto entre a pasta que contém _ViewImports.cshtml e a pasta que contém a página.The rest of the generated namespace (the suffix portion) is the dot-separated relative path between the folder containing _ViewImports.cshtml and the folder containing the page.

Por exemplo, a classe PageModel Pages/Customers/Edit.cshtml.cs define explicitamente o namespace:For example, the PageModel class Pages/Customers/Edit.cshtml.cs explicitly sets the namespace:

namespace RazorPagesContacts.Pages
{
    public class EditModel : PageModel
    {
        private readonly AppDbContext _db;

        public EditModel(AppDbContext db)
        {
            _db = db;
        }

        // Code removed for brevity.

O arquivo Pages/_ViewImports.cshtml define o namespace a seguir:The Pages/_ViewImports.cshtml file sets the following namespace:

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

O namespace gerado para o Razor Pages Pages/Customers/Edit.cshtml é o mesmo que a classe PageModel.The generated namespace for the Pages/Customers/Edit.cshtml Razor Page is the same as the PageModel class.

@namespace também funciona com exibições do Razor convencionais.@namespace also works with conventional Razor views.

O arquivo de exibição Pages/Create.cshtml original:The original Pages/Create.cshtml view file:

@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>

O arquivo de exibição Pages/Create.cshtml atualizado:The updated Pages/Create.cshtml view file:

@page
@model CreateModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>

O projeto inicial de Páginas do Razor contém o Pages/_ValidationScriptsPartial.cshtml, que conecta a validação do lado do cliente.The Razor Pages starter project contains the Pages/_ValidationScriptsPartial.cshtml, which hooks up client-side validation.

Para obter mais informações sobre exibições parciais, consulte Exibições parciais no ASP.NET Core.For more information on partial views, see Exibições parciais no ASP.NET Core.

Geração de URL para PáginasURL generation for Pages

A página Create, exibida anteriormente, usa RedirectToPage:The Create page, shown previously, uses RedirectToPage:

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

    _db.Customers.Add(Customer);
    await _db.SaveChangesAsync();
    return RedirectToPage("/Index");
}

O aplicativo tem a estrutura de arquivos/pastas a seguir:The app has the following file/folder structure:

  • /Pages/Pages

    • Index.cshtmlIndex.cshtml

    • /Clientes/Customers

      • Create.cshtmlCreate.cshtml
      • Edit.cshtmlEdit.cshtml
      • Index.cshtmlIndex.cshtml

As páginas Pages/Customers/Create.cshtml e Pages/Customers/Edit.cshtml redirecionam para o Pages/Index.cshtml após êxito.The Pages/Customers/Create.cshtml and Pages/Customers/Edit.cshtml pages redirect to Pages/Index.cshtml after success. A cadeia de caracteres /Index faz parte do URI para acessar a página anterior.The string /Index is part of the URI to access the preceding page. A cadeia de caracteres /Index pode ser usada para gerar URIs para a página Pages/Index.cshtml.The string /Index can be used to generate URIs to the Pages/Index.cshtml page. Por exemplo:For example:

  • Url.Page("/Index", ...)
  • <a asp-page="/Index">My Index Page</a>
  • RedirectToPage("/Index")

O nome da página é o caminho para a página da pasta raiz /Pages, incluindo um / à direita (por exemplo, /Index).The page name is the path to the page from the root /Pages folder including a leading / (for example, /Index). Os exemplos anteriores de geração de URL oferecem opções avançadas e recursos funcionais para codificar uma URL.The preceding URL generation samples offer enhanced options and functional capabilities over hardcoding a URL. A geração de URL usa roteamento e pode gerar e codificar parâmetros de acordo com o modo como a rota é definida no caminho de destino.URL generation uses routing and can generate and encode parameters according to how the route is defined in the destination path.

A Geração de URL para páginas dá suporte a nomes relativos.URL generation for pages supports relative names. A tabela a seguir mostra qual página de Índice é selecionada com diferentes parâmetros RedirectToPage de Pages/Customers/Create.cshtml:The following table shows which Index page is selected with different RedirectToPage parameters from Pages/Customers/Create.cshtml:

RedirectToPage(x)RedirectToPage(x) PáginaPage
RedirectToPage("/Index")RedirectToPage("/Index") Pages/IndexPages/Index
RedirectToPage("./Index");RedirectToPage("./Index"); Pages/Customers/IndexPages/Customers/Index
RedirectToPage("../Index")RedirectToPage("../Index") Pages/IndexPages/Index
RedirectToPage("Index")RedirectToPage("Index") Pages/Customers/IndexPages/Customers/Index

RedirectToPage("Index"), RedirectToPage("./Index") e RedirectToPage("../Index") são nomes relativos.RedirectToPage("Index"), RedirectToPage("./Index"), and RedirectToPage("../Index") are relative names. O parâmetro RedirectToPage é combinado com o caminho da página atual para calcular o nome da página de destino.The RedirectToPage parameter is combined with the path of the current page to compute the name of the destination page.

Vinculação de nome relativo é útil ao criar sites com uma estrutura complexa.Relative name linking is useful when building sites with a complex structure. Se você usar nomes relativos para vincular entre páginas em uma pasta, você poderá renomear essa pasta.If you use relative names to link between pages in a folder, you can rename that folder. Todos os links ainda funcionarão (porque eles não incluirão o nome da pasta).All the links still work (because they didn't include the folder name).

Para redirecionar para uma página em uma área diferente, especifique essa área:To redirect to a page in a different Area, specify the area:

RedirectToPage("/Index", new { area = "Services" });

Para obter mais informações, consulte Áreas no ASP.NET Core.For more information, see Áreas no ASP.NET Core.

Atributo ViewDataViewData attribute

Os dados podem ser passados para uma página com ViewDataAttribute.Data can be passed to a page with ViewDataAttribute. As propriedades nos controladores ou nos modelos da Página Razor decoradas com [ViewData] têm seus valores armazenados e carregados em ViewDataDictionary.Properties on controllers or Razor Page models decorated with [ViewData] have their values stored and loaded from the ViewDataDictionary.

No exemplo a seguir, o AboutModel contém uma propriedade Title decorada com [ViewData].In the following example, the AboutModel contains a Title property decorated with [ViewData]. A propriedade Title está definida como o título da página Sobre:The Title property is set to the title of the About page:

public class AboutModel : PageModel
{
    [ViewData]
    public string Title { get; } = "About";

    public void OnGet()
    {
    }
}

Na página Sobre, acesse a propriedade Title como uma propriedade de modelo:In the About page, access the Title property as a model property:

<h1>@Model.Title</h1>

No layout, o título é lido a partir do dicionário ViewData:In the layout, the title is read from the ViewData dictionary:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>@ViewData["Title"] - WebApplication</title>
    ...

TempDataTempData

O ASP.NET Core expõe a propriedade TempData em um controlador.ASP.NET Core exposes the TempData property on a controller. Essa propriedade armazena dados até eles serem lidos.This property stores data until it's read. Os métodos Keep e Peek podem ser usados para examinar os dados sem exclusão.The Keep and Peek methods can be used to examine the data without deletion. TempData é útil para redirecionamento nos casos em que os dados são necessários para mais de uma única solicitação.TempData is useful for redirection, when data is needed for more than a single request.

O atributo [TempData] é novo no ASP.NET Core 2.0 e tem suporte em controladores e páginas.The [TempData] attribute is new in ASP.NET Core 2.0 and is supported on controllers and pages.

Os conjuntos de código a seguir definem o valor de Message usando TempData:The following code sets the value of Message using TempData:

public class CreateDotModel : PageModel
{
    private readonly AppDbContext _db;

    public CreateDotModel(AppDbContext db)
    {
        _db = db;
    }

    [TempData]
    public string Message { get; set; }

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

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

        _db.Customers.Add(Customer);
        await _db.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";
        return RedirectToPage("./Index");
    }
}

A marcação a seguir no arquivo Pages/Customers/Index.cshtml exibe o valor de Message usando TempData.The following markup in the Pages/Customers/Index.cshtml file displays the value of Message using TempData.

<h3>Msg: @Model.Message</h3>

O modelo de página Pages/Customers/Index.cshtml.cs aplica o atributo [TempData] à propriedade Message.The Pages/Customers/Index.cshtml.cs page model applies the [TempData] attribute to the Message property.

[TempData]
public string Message { get; set; }

Para obter mais informações, confira TempData.For more information, see TempData .

Vários manipuladores por páginaMultiple handlers per page

A página a seguir gera marcação para dois manipuladores de página usando o auxiliar de marcas asp-page-handler:The following page generates markup for two page handlers using the asp-page-handler Tag Helper:

@page
@model CreateFATHModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
    </form>
</body>
</html>

O formulário no exemplo anterior tem dois botões de envio, cada um usando o FormActionTagHelper para enviar para uma URL diferente.The form in the preceding example has two submit buttons, each using the FormActionTagHelper to submit to a different URL. O atributo asp-page-handler é um complemento para asp-page.The asp-page-handler attribute is a companion to asp-page. asp-page-handler gera URLs que enviam para cada um dos métodos de manipulador definidos por uma página.asp-page-handler generates URLs that submit to each of the handler methods defined by a page. asp-page não foi especificado porque a amostra está vinculando à página atual.asp-page isn't specified because the sample is linking to the current page.

O modelo de página:The page model:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages.Customers
{
    public class CreateFATHModel : PageModel
    {
        private readonly AppDbContext _db;

        public CreateFATHModel(AppDbContext db)
        {
            _db = db;
        }

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

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

            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();
            return RedirectToPage("/Index");
        }

        public async Task<IActionResult> OnPostJoinListUCAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            Customer.Name = Customer.Name?.ToUpper();
            return await OnPostJoinListAsync();
        }
    }
}

O código anterior usa métodos de manipulador nomeados.The preceding code uses named handler methods. Métodos de manipulador nomeados são criados colocando o texto no nome após On<HTTP Verb> e antes de Async (se houver).Named handler methods are created by taking the text in the name after On<HTTP Verb> and before Async (if present). No exemplo anterior, os métodos de página são OnPostJoinListAsync e OnPostJoinListUCAsync.In the preceding example, the page methods are OnPostJoinListAsync and OnPostJoinListUCAsync. Com OnPost e Async removidos, os nomes de manipulador são JoinList e JoinListUC.With OnPost and Async removed, the handler names are JoinList and JoinListUC.

<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />

Usando o código anterior, o caminho da URL que envia a OnPostJoinListAsync é http://localhost:5000/Customers/CreateFATH?handler=JoinList.Using the preceding code, the URL path that submits to OnPostJoinListAsync is http://localhost:5000/Customers/CreateFATH?handler=JoinList. O caminho da URL que envia a OnPostJoinListUCAsync é http://localhost:5000/Customers/CreateFATH?handler=JoinListUC.The URL path that submits to OnPostJoinListUCAsync is http://localhost:5000/Customers/CreateFATH?handler=JoinListUC.

Rotas personalizadasCustom routes

Use a diretiva @page para:Use the @page directive to:

  • Especifique uma rota personalizada para uma página.Specify a custom route to a page. Por exemplo, a rota para a página Sobre pode ser definida como /Some/Other/Path com @page "/Some/Other/Path".For example, the route to the About page can be set to /Some/Other/Path with @page "/Some/Other/Path".
  • Acrescente segmentos à rota padrão de uma página.Append segments to a page's default route. Por exemplo, um segmento de "item" pode ser adicionado à rota padrão da página com @page "item".For example, an "item" segment can be added to a page's default route with @page "item".
  • Acrescente parâmetros à rota padrão de uma página.Append parameters to a page's default route. Por exemplo, um parâmetro de ID, id, pode ser necessário para uma página com @page "{id}".For example, an ID parameter, id, can be required for a page with @page "{id}".

Há suporte para um caminho relativo à raiz designado por um til (~) no início do caminho.A root-relative path designated by a tilde (~) at the beginning of the path is supported. Por exemplo, @page "~/Some/Other/Path" é o mesmo que @page "/Some/Other/Path".For example, @page "~/Some/Other/Path" is the same as @page "/Some/Other/Path".

Você pode alterar a cadeia de caracteres de consulta ?handler=JoinList na URL para um segmento de rota /JoinList ao especificar o modelo de rota @page "{handler?}".You can change the query string ?handler=JoinList in the URL to a route segment /JoinList by specifying the route template @page "{handler?}".

Se você não deseja a cadeia de consulta ?handler=JoinList na URL, você pode alterar a rota para colocar o nome do manipulador na parte do caminho da URL.If you don't like the query string ?handler=JoinList in the URL, you can change the route to put the handler name in the path portion of the URL. Você pode personalizar a rota adicionando um modelo de rota entre aspas duplas após a diretiva @page.You can customize the route by adding a route template enclosed in double quotes after the @page directive.

@page "{handler?}"
@model CreateRouteModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
    </form>
</body>
</html>

Usando o código anterior, o caminho da URL que envia a OnPostJoinListAsync é http://localhost:5000/Customers/CreateFATH/JoinList.Using the preceding code, the URL path that submits to OnPostJoinListAsync is http://localhost:5000/Customers/CreateFATH/JoinList. O caminho da URL que envia a OnPostJoinListUCAsync é http://localhost:5000/Customers/CreateFATH/JoinListUC.The URL path that submits to OnPostJoinListUCAsync is http://localhost:5000/Customers/CreateFATH/JoinListUC.

O ? após handler significa que o parâmetro de rota é opcional.The ? following handler means the route parameter is optional.

Configuração e definiçõesConfiguration and settings

Para configurar opções avançadas, use o método de extensão AddRazorPagesOptions no construtor de MVC:To configure advanced options, use the extension method AddRazorPagesOptions on the MVC builder:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddRazorPagesOptions(options =>
        {
            options.RootDirectory = "/MyPages";
            options.Conventions.AuthorizeFolder("/MyPages/Admin");
        });
}

No momento, você pode usar o RazorPagesOptions para definir o diretório raiz para páginas ou adicionar as convenções de modelo de aplicativo para páginas.Currently you can use the RazorPagesOptions to set the root directory for pages, or add application model conventions for pages. Permitiremos mais extensibilidade dessa maneira no futuro.We'll enable more extensibility this way in the future.

Para pré-compilar exibições, consulte Compilação de exibição do Razor.To precompile views, see Razor view compilation .

Baixar ou exibir código de exemplo.Download or view sample code.

Consulte a Introdução a Páginas do Razor, que se baseia nesta introdução.See Get started with Razor Pages, which builds on this introduction.

Especificar que as Páginas Razor estão na raiz do conteúdoSpecify that Razor Pages are at the content root

Por padrão, as Páginas Razor estão na raiz do diretório /Pages.By default, Razor Pages are rooted in the /Pages directory. Adicione WithRazorPagesAtContentRoot em AddMvc para especificar que as Páginas Razor estão na raiz do conteúdo (ContentRootPath) do aplicativo:Add WithRazorPagesAtContentRoot to AddMvc to specify that your Razor Pages are at the content root (ContentRootPath) of the app:

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        ...
    })
    .WithRazorPagesAtContentRoot();

Especificar que as Páginas Razor estão em um diretório raiz personalizadoSpecify that Razor Pages are at a custom root directory

Adicione WithRazorPagesRoot em AddMvc para especificar que as Páginas Razor estão em um diretório raiz personalizado no aplicativo (forneça um caminho relativo):Add WithRazorPagesRoot to AddMvc to specify that your Razor Pages are at a custom root directory in the app (provide a relative path):

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        ...
    })
    .WithRazorPagesRoot("/path/to/razor/pages");

Recursos adicionaisAdditional resources