Blazor Server - CRUD com Entity Framework Core 3.1 - I

Hoje vamos criar uma aplicação Blazor do lado do servidor e realizar um CRUD usando o EF Core 3.1.

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.  

Hoje vou mostrar 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 3.1

Vamos acessar dados de um banco de dados SQL Server já existente chamado Cadastro e gerenciar as informações da tabela Estudantes que possui a seguinte estrutura e dados:

Assim vamos criar uma aplicação do lado do servidor e referenciar o EF Core no projeto.

Recursos usados:

Criando o projeto Blazor o VS Community 2019

Abra o VS 2019 Community (versão mínima 16.4) e selecione a opção Create a New Project;

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

Informe o nome do projeto :  Blazor_Crud1, a localização e clique em Create;

A seguir teremos uma janela com duas opções :

  1. Blazor Server App
  2. Blazor WebAssembly App

Selecione a primeira opção - Blazor Server App. Não vamos usar autenticação nem habilitar o https.

Clique no botão Create para criar o projeto.

Ao final teremos o projeto criado com a estrutura abaixo:

A pasta wwwroot é onde os recursos estáticos usados pela aplicação são colocados.

As pastas Pages e Shared são as mais importantes do projeto e contém componentes que são arquivos com a extensão .razor.

Na pasta Pages temos os componentes roteados, ou seja, que possuem uma rota definida usando a diretiva @page.

Na pasta Shared temos os componentes não roteados e que podem ser compartilhados com os demais componentes.

Na pasta Data é onde colocamos os dados que a aplicação vai usar.

O arquivo _Imports.razor é onde definimos os namespaces que poderão ser compartilhados com todos os componentes.

O arquivo App.razor é esta definindo o roteamento e o layout padrão usado no projeto.

No arquivo Startup.cs podemos configurar serviços e recursos da mesma forma que fazemos na ASP .NET Core.

Incluindo as referências ao EF Core

Para incluir a referência ao EF Core acione o menu Tools -> Manage Nuget Package for Solutions e clique na guia Browse e a seguir informe o nome do pacote: Microsoft.EntityFrameworkCore.Server

Clique em Install para instalar o pacote e suas dependências.

Repita o procedimento e instale também os pacotes:

  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.AspNetCore.Blazor.HttpClient

Este último pacote é necessário para podermos ter acesso aos métodos GetJsonAsycn(), PostJsonAsync(), etc. no pacote HttpClient.

Ajustando o projeto criado

Será criado um projeto padrão que vamos ajustar da seguinte forma:

  • Na pasta Pages vamos remover os arquivos FetchData.razor, Error.razor e Counter.razor;
  • Na pasta Data vamos remover todos os arquivos existentes;
  • No arquivo Startup no método ConfigureServices, remova a referência ao serviço : WeatherForecastService

No arquivo NavMenu, na pasta Shared, é onde definimos os links para o menu da aplicação. Vamos alterar o conteúdo deste arquivo conforme abaixo:

<div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">Blazor_Questionario</a>
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>
<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-calculator" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="/alunos">
                <span class="oi oi-book" aria-hidden="true"></span> Alunos
            </NavLink>
        </li>
    </ul>
</div>
@code {
    bool collapseNavMenu = true;
    string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
    void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }

Alteramos o código do menu para exibir os links com os textos: Home e Alunos

Finalmente na pasta wwwroot crie uma pasta imagens e inclua as duas imagens que vamos usar no projeto:

Definindo o modelo de dados e o contexto

Vamos criar o arquivo Estudante.cs na pasta Data onde vamos definir o modelo de dados que iremos usar no projeto e que será usado como DTO (data transfer object).

    public class Estudante
    {
        public int EstudanteId { get; set; }
        public string Nome { get; set; }
        public string Email { get; set; }
        public int Idade { get; set; }
    }

Criamos a classe Estudante com as propriedades que serão mapeadas para a tabela Estudantes.

Agora vamos criar o arquivo de contexto que vai permitir realizar a conexão com a tabela do banco de dados a partir da nossa entidade segundo o mapeamento feito usando DbSet.

Na pasta Data crie o arquivo AppDbContext.cs e inclua o código abaixo:

   public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options)
          : base(options)
        {
        }
        public DbSet<Estudante> Estudantes { get; set; }
    }

A classe herda de DbContext e define o mapeamento da entidade para a tabela.

Agora precisamos definir a string de conexão com o banco de dados SQL Server no arquivo appsettings.json:

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

Finalmente podemos registrar o contexto como um serviço no método ConfigureServices da classe Startup:

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

Agora precisamos fazer um ajuste para poder injetar o serviço HttpClient no projeto incluindo o código abaixo no arquivo Startup no método ConfigureServices() :

          ...
          // Projeto Server Side não registrar o HttpClient por padrão
            if (!services.Any(x => x.ServiceType == typeof(HttpClient)))
            {
                // Configura o HttpClient para o lado do servidor 
                services.AddScoped<HttpClient>(s =>
                {
                    var uriHelper = s.GetRequiredService<NavigationManager>();
                    return new HttpClient
                    {
                        BaseAddress = new Uri(uriHelper.BaseUri)
                    };
                });
            }
          ...

Sem a configuração acima, ao tentar injetar o serviço HttpClient no componente iremos obter a seguinte mensagem de erro: There is no registered service of type 'System.Net.Http.HttpClient'.

Pronto, com essas configurações já podemos acessar os dados e vamos agora definir os componentes usados no projeto.

Criando o controlador EstudanteController

Vamos criar uma Web API chamada EstudanteController para termos acesso aos dados dos alunos e podermos realizarmos o CRUD.

Para simplificar o projeto vamos criar essa API usando os recursos do Scaffold do EF Core na pasta Data.

Clique com o botão direito do mouse sobre a pasta Data e a seguir em Add -> Controller;

Selecione a última opção da janela Add New Scaffolded Item => API Controller with Actions, using Entity Framework e clique no botão Add;

Na próxima janela informe os dados conforme mostrado na figura a seguir:

Clique no botão Add;

Será criado o controlador (WEb API) EstudanteController na pasta Data contendo os métodos para realizar a inclusão, alteração e exclusão via métodos HTTP, e, agora poderemos realizar as operações CRUD acessando esta API.

Após isso não esqueça de incluir no método Configure da classe Startup a definição do endpoint para os Controladores:

...
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
...

Alterando o código do componente Index.razor

Agora vamos começar pelo componente Index.razor onde vamos exibir apenas uma imagem e um texto.

@page "/"
<img src="/imagens/alunos1.jpg" />
<br />
<h4>Cadastro de Alunos..</h4>

Criando o componente Alunos

Para exibir os dados dos alunos existentes na tabela Estudantes vamos criar o componente Alunos.razor na pasta Pages e a seguir incluir o código abaixo:

@page "/alunos"
@inject HttpClient  http
<h3>Alunos</h3>
<p>
    <a href="/addaluno">Criar Novo Aluno</a>
</p>
@if (alunos == null)
{
    <img src="/imagens/basicloader.gif" />
}
else
{
    <table class='table'>
        <thead>
            <tr>
                <th>Nome</th>
                <th>Email</th>
                <th>Idade</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var aluno in alunos)
            {
                <tr>
                    <td>@aluno.Nome</td>
                    <td>@aluno.Email</td>
                    <td>@aluno.Idade</td>
                    <td>
                        <a href='/editaluno/@aluno.EstudanteId'>Edita</a>
                        <a href='/deletealuno/@aluno.EstudanteId'>Deleta</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
}
@code {
    List<Estudante> alunos;
    protected override async Task OnInitializedAsync()
    {
        alunos = await http.GetJsonAsync<List<Estudante>>("/api/estudante");
    }
} 

Neste código usamos o evento OnInitializedAsync para obter os dados dos alunos usando o método GetJsonAsync do serviço HttpClient que vai retornar uma lista de alunos a partir da nossa API que é acessada pelo endpoint /api/estudante.

Executando o projeto teremos o resultado abaixo:

Na próxima parte do artigo vamos definir os demais componentes e realizar as operações CRUD, iniciando com o componente para incluir um novo aluno.

Pegue o código do projeto aqui: Blazor_Crud1_1.zip  (sem as referências)

"Quem ama a sua vida perdê-la-á, e quem neste mundo odeia a sua vida, guardá-la-á para a vida eterna.
Se alguém me serve, siga-me, e onde eu estiver, ali estará também o meu servo. E, se alguém me servir, meu Pai o honrará."
João 12:25,26

 


Referências:


José Carlos Macoratti