ASP .NET Core - Apresentando Razor Pages - II

 Neste artigo eu vou apresentar o novo recurso Razor Pages da ASP .NET Core.

Continuando a primeira parte do artigo vamos usar o projeto Razor Page criado e definir uma aplicação básica para gerenciar informações de clientes.

Nota: O projeto deste artigo foi baseado no original em : https://docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/?tabs=visual-studio com ajustes e modificações.

Os recursos das Razor Pages foram projetados para facilitar a utilização dos padrões comuns usados com os navegadores. Assim o Model binding, as Tag Helpers e os HTML helpers, todos funcionam com as propriedades definidas em uma classe Razor Page.

Vamos então partir do projeto padrão criado no artigo anterior e implementar o CRUD básico para gerenciar informações de Clientes.

Recursos usados:

Ajustando o projeto para gerenciar informações de clientes

Abra o projeto AspnRazorPage1 criado na primeira parte do artigo e inclua uma pasta Models no projeto. (Project-> New Folder)

Crie a classe Cliente que vai representar um cliente do nosso modelo de domínio com o seguinte código:

using System.ComponentModel.DataAnnotations;
namespace AspnRazorPage1.Models
{
    public class Cliente
    {
        public int Id { get; set; }
        [Required, StringLength(100)]
        public string Nome { get; set; }
    }
}

A seguir vamos criar a classe de contexto chamada AppDbContext que herda de DbContext na pasta Models com o código abaixo:

using Microsoft.EntityFrameworkCore;
namespace AspnRazorPage1.Models
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions options) : base(options)
        {
        }
        public DbSet<Cliente> Clientes { get; set; }
    }
}

Agora vamos configurar o método ConfigureServices da classe Startup.cs definindo a inicialização do DbContext:

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>(options =>
                              options.UseInMemoryDatabase("ClientesDados"));
            services.AddMvc();
        }

Registramos o nosso contexto como um serviço e usamos um novo recurso do Entity Framework Core que é o provedor de dados em memória (in-memory). Como nossa aplicação é basicamente um protótipo não precisamos configurar um banco de dados local ou externo, e, por isso vamos usar os dados em memória. (Para isso estamos usando o pacote Microsoft.EntityFrameworkCore.InMemory que já esta incluso no projeto.)

Incluindo uma nova Razor Page : Create.cshtml

Vamos agora incluir uma página chamada Create.chstml na pasta Pages.

Clique com o botão direito do mouse sobre a pasta Pages a seguir clique em Add -> Razor Page

A seguir na janela Add Scaffold clique em Razor Page e a seguir no botão Add;

Na janela Add Razor Page informe o nome Create e marque as opções conforme a figura a seguir:

Clicando no botão Add teremos a view Create.cshtml e seu arquivo code-behind criados na pasta Pages.

Vamos iniciar definindo o código do arquivo code-behind Create.cshtml.cs :

using AspnRazorPage1.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Threading.Tasks;
namespace AspnRazorPage1.Pages
{
    public class CreateModel : PageModel
    {
        private readonly AppDbContext _db;
        public CreateModel(AppDbContext db)
        {
            _db = db;
        }
        [BindProperty]
        public Cliente Cliente { get; set; }
        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            _db.Clientes.Add(Cliente);
            await _db.SaveChangesAsync();
            return RedirectToPage("/Index");
        }
    }
}

Por convenção, a classe PageModel é chamada <PageName>Model, no exemplo:  <Create>Model, e está no mesmo namespace da página.

A classe PageModel permite a separação da lógica de uma página de sua apresentação. Ela define manipuladores de página para requisições enviadas para a página e os dados usados ​​para renderizar a página. (Esta separação permite gerir dependências de páginas através da injeção de dependência e testar as páginas.)

A página possui um método OnPostAsync, que é executado em requisições POST (quando um usuário publica o formulário). Você pode adicionar métodos de manipulador para qualquer verbo HTTP.

O sufixo de nomeação Async é opcional, mas geralmente é usado por convenção para funções assíncronas. O código OnPostAsync é semelhante ao que você normalmente escreveria em um controlador. O código anterior é típico das Razor Pages. A maioria dos recursos do MVC, como o Model Binding , a validação e os action results, são compartilhados.

No método OnPostAsync: temos a verificação para validação de erros com as seguintes ações:

1 - Se não houver erros, salva os dados e faz o redirecionamento
2 - Se houver erros, exibe a página novamente com as mensagens de validação. (A validação do lado do cliente é idêntica às feitas nas aplicações ASP.NET Core MVC. Em muitos casos, erros de validação seriam detectados no cliente.)

Quando os dados são inseridos com sucesso, o método do manipulador OnPostAsync chama o método helper redirectToPage para retornar uma instância de RedirectToPageResult.

Aqui, RedirectToPage é um novo action result, semelhante ao RedirectToAction ou RedirectToRoute, mas personalizado para páginas. No código estamos redirecionando para a página Index da raiz (/Index).

Quando o formulário enviado tiver erros de validação (que são passados ​​para o servidor), o método OnPostAsync chama o método Page Helper e Page retorna uma instância do PageResult. PageResult é o tipo de retorno padrão para um método de manipulador. Um método de manipulador que retorna void renderiza a página.

Observe que a propriedade Cliente utiliza o atributo [BindProperty] para ativar o model binding.

Agora abra o arquivo Create.cshtml e inclua o código abaixo:

@page
@model AspnRazorPage1.Pages.CreateModel
@{
    ViewData["Title"] = "Criar";
}
<html>
<body>
    <p>
        Informe seu nome
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Nome: <input asp-for="Cliente.Nome" /></div>
        <input type="submit" />
    </form>
</body>
</html>

Por padrão as Razor Pages, vincula as propriedades somente com verbos que não são do tipo GET. Essa vinculação de propriedades pode reduzir a quantidade de código que você precisa escrever, pois ela reduz o código usando a mesma propriedade para renderizar campos de formulário (<input asp-for = "Cliente.Nome" />) e aceita a entrada de dados.

Vamos agora alterar o código da página Index.cshtml existente na pasta Pages conforme abaixo:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}
<h2>Contatos</h2>
<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Nome</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var contato in Model.Clientes)
            {
                <tr>
                    <td>@contato.Id</td>
                    <td>@contato.Nome</td>
                    <td>
                        <a asp-page="./Edit" asp-route-id="@contato.Id">Editar</a>
                        <button type="submit" asp-page-handler="delete" asp-route-id="@contato.Id">Deletar</button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <a asp-page="./Create">Criar Contato</a>
</form>

Nesta view Index.cshtml definimos o PageModel como IndexModel e a propriedade Clientes que será definida no code-behind onde estamos exibindo o Id e Nome do Cliente.

Para editar e/ou deletar usamos o asp-route-id para passar o Id do cliente para a página.

A seguir inclua o código abaixo no arquivo code-behind Index.cshtml.cs :
 
using AspnRazorPage1.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace AspnRazorPage1.Pages
{
    public class IndexModel : PageModel
    {
        private readonly AppDbContext _db;
        public IndexModel(AppDbContext db)
        {
            _db = db;
        }
        public IList<Cliente> Clientes { get; private set; }
        public async Task OnGetAsync()
        {
            Clientes = await _db.Clientes.AsNoTracking().ToListAsync();
        }
        public async Task<IActionResult> OnPostDeleteAsync(int id)
        {
            var contact = await _db.Clientes.FindAsync(id);
            if (contact != null)
            {
                _db.Clientes.Remove(contact);
                await _db.SaveChangesAsync();
            }
            return RedirectToPage();
        }
    }
}

No arquivo code-behind injetamos uma instância do nosso contexto no construtor e definimos os métodos OnGetAsync() para exibir os clientes e OnPostDeleteAsync() que vai localizar o cliente e deletar suas informações.

Executando o nosso projeto neste momento teremos o seguinte resultado:

1- Exibição da view Index.cshtml

2- Exibição da view Create.cshtml após clicar no link - Criar Contato

 

3- Exibição da view Index.cshtm após incluir um  novo contato

Na próxima parte do artigo vamos continuar nossa aplicação criando a página para editar informações do cliente.

Todavia digo-vos a verdade, que vos convém que eu vá; porque, se eu não for, o Consolador não virá a vós; mas, quando eu for, vo-lo enviarei.
E, quando ele vier, convencerá o mundo do pecado, e da justiça e do juízo.
Do pecado, porque não crêem em mim;
Da justiça, porque vou para meu Pai, e não me vereis mais;

João 16:7-10

 

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?


Referências:


José Carlos Macoratti