Blazor Server - CRUD com EFCore com Modal Dialog


Neste artigo vamos criar uma aplicação Blazor Server e realizar um CRUD usando o EF Core e os recursos do jQuery e Bootstrap.

Se você esta chegando agora e não sabe o que é o Blazor leia o artigo ASP .NET Core - Iniciando com o Blazor - Macoratti; se você já conhece e quer saber mais pode fazer o meu curso de Blazor Essencial.  

Criando um projeto Blazor Server

Hoje vou mostrar mais uma vez como é simples criar uma aplicação SPA (Single Page Application) no Blazor usando o template Blazor Server e realizar as operações CRUD com o auxílio do EF Core.

Vamos criar um projeto centrado nos dados onde vamos mesclar várias responsabilidades em um projeto Blazor. Estamos apenas nos divertindo aqui para mostrar alguns recursos do Blazor.

Abra o VS 2019 Community e selecione a opção Create a New Project;

A seguir selecione a opção Blazor Server App e clique em next;

Informe o nome do projeto Blazor_Tarefas igual ao da Solução e clique em Next;

Defina as configurações conforme mostrado na figura abaixo e clique em Create;

Teremos a solução e o projeto criados em uma arquitetura monolítica de projeto único com a seguinte estrutura exibida na janela Solution Explorer:

Limpando o projeto

Vamos limpar o projeto criado deixando apenas os componentes Index.razor na pasta Pages e removendo todos os arquivos da pasta Data. Após isso teremos que  remover as referências nos arquivos do projeto aos arquivos excluídos.

Vamos ajustar o arquivo NavMenu.razor da pasta Shared deixando apenas dois links definidos: Home e Tarefas

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="tarefas">
                <span class="oi oi-document" aria-hidden="true"></span> Tarefas
            </NavLink>
        </li>
    </ul>
</div>

Configurando o EF Core e criando o domínio e o contexto

A seguir vamos incluir no projeto os seguintes pacotes:

Estamos usando a versão do EF Core 5.0.4 para todos os pacotes.

A seguir na pasta Data vamos criar a classe Tarefa que será o nosso modelo de domínio totalmente anêmico  contendo apenas as seguintes propriedades definidas:

using System;
using System.ComponentModel.DataAnnotations;
namespace Blazor_Tarefas.Data
{
    public class Tarefa
    {
        [Key]
        public int Id { get; set; }
        [Required(ErrorMessage = "Informe o nome da tarefa")]
        [StringLength(30, ErrorMessage = "Nome é muito longo.")]
        public string Nome { get; set; }
        [Required(ErrorMessage = "O status é obrigatório")]
        [MaxLenght(30)]
        public string Status { get; set; }
        [Required(ErrorMessage = "A data de conclusão tem que ser informada")]
        public DateTime DataConclusao { get; set; }
    }
}

Aqui já tascamos as anotações de dados usando o Data Annotations para agilizar a validação da entrada dos dados.

Precisamos agora criar o famoso arquivo de contexto que vai herdar de DbContext do EF Core e vai permitir fazer o mapeamento ORM poupando muito trabalho.

Assim na pasta Data vamos criar a classe AppDbContext com seguinte código:

using Microsoft.EntityFrameworkCore;
namespace Blazor_Tarefas.Data
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options)
           : base(options)
        {
        }
        public DbSet<Tarefa> ListaTarefas { get; set; }
        public override int SaveChanges()
        {
            return base.SaveChanges();
        }
    }
}

Na classe de contexto AppDbContext já definimos o parâmetros options onde vamos passar a string de conexão e o provedor para o banco de dados usado e definimos o mapeamento para a tabela ListaTarefas que iremos criar usando o Code-First.

Agora, como você já sabe, vamos registrar as opções e o serviço do contexto no método ConfigureServices da classe Startup :

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>(options =>
               options.UseSqlServer(
                   Configuration.GetConnectionString("DefaultConnection")));
            services.AddRazorPages();
            services.AddServerSideBlazor();
        }

Só falta agora criar no arquivo appsettings.json a string de conexão definindo a seção ConnectionStrings:

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=desktop\\sqlexpress;Initial Catalog=TarefasDB;Integrated Security=True"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Nota: Aqui você vai usar a sua string de conexão.

Pronto , fizemos tudo isso e chegamos até aqui apenas para aplicar o Migrations e gerar o banco de dados TarefasDB e a tabela ListaTarefas.

Assim digite os comandos a seguir, um após o outro, na janela do Package Manager Console:

add-migration Inicial
update-database

Ao final do processamento teremos o banco e a tabela criados. Para conferir abra o Server Explorer no VS 2019.

Criando os serviços

Vamos criar uma pasta Services no projeto e nesta pasta vamos criar a interface ITarefasService e a sua implementação na classe concreta TarefasService.

using Blazor_Tarefas.Data;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Blazor_Tarefas.Services
{
    public interface ITarefasService
    {
        Task<List<Tarefa>> Get();
        Task<Tarefa> Get(int id);
        Task<Tarefa> Add(Tarefa toDo);
        Task<Tarefa> Update(Tarefa toDo);
        Task<Tarefa> Delete(int id);
    }
}

Note que definimos um contrato para realizar o CRUD básico e de forma assíncrona visto que usamos a classe Task que representa uma operação assíncrona e que não retorna um valor.

A implementação desta interface na classe TarefasService vem a seguir:

using Blazor_Tarefas.Data;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Blazor_Tarefas.Services
{
    public class TarefasService : ITarefasService
    {
        private readonly AppDbContext _context;
        public TarefasService(AppDbContext context)
        {
            _context = context;
        }

        public async Task<List<Tarefa>> Get()
        {
            return await _context.ListaTarefas.ToListAsync();
        }
        public async Task<Tarefa> Get(int id)
        {
            var tarefa = await _context.ListaTarefas.FindAsync(id);
            return tarefa;
        }
        public async Task<Tarefa> Add(Tarefa tarefa)
        {
            _context.ListaTarefas.Add(tarefa);
            await _context.SaveChangesAsync();
            return tarefa;
        }
        public async Task<Tarefa> Update(Tarefa tarefa)
        {
            _context.Entry(tarefa).State = EntityState.Modified;
            await _context.SaveChangesAsync();
            return tarefa;
        }
        public async Task<Tarefa> Delete(int id)
        {
            var tarefa = await _context.ListaTarefas.FindAsync(id);
            _context.ListaTarefas.Remove(tarefa);
            await _context.SaveChangesAsync();
            return tarefa;
        }
    }
}

Aqui injetamos uma instância do nosso contexto AppDbContext e estamos realizando a inclusão, edição, exclusão e consulta dos dados.

Já temos quase tudo pronto para acessar os dados na próxima parte do artigo vamos fazer alguns ajustes no projeto e criar o componente Blazor para exibir a lista de tarefas.

"E, ao pôr do sol, todos os que tinham enfermos de várias doenças lhos traziam; e, pondo as mãos sobre cada um deles, 'Jesus' os curava."
Lucas 4:40

Referências:


José Carlos Macoratti