Construindo uma aplicação Web completa com Blazor — Parte 2

Salve galera! Continuando nossa aplicação Web com Blazor, vamos implementar nossas classes de domínio e acesso ao banco de dados, de forma rápida para podermos seguir rápido e utilizar o Blazor pra valer.

GitHub

O projeto está disponível no GitHub, com cada parte da série em uma branch, sendo a master atualizada sempre com a última parte publicada. Segue a URL do repositório:

Antes de começar…

Antes de começarmos a segunda parte, muitas pessoas me perguntaram quando ao uso do Visual Studio Code, CLI do .NET Core, etc. Vamos ver de forma rápida como criar a mesma estrutura que fizemos e aprendemos na parte 1, mas com o CLI do .NET Core e o Visual Studio Code, ok?

Para começar, precisamos instalar / atualizar os templates do Blazor para o .NET CLI. Para isso, basta executar o comando abaixo:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates

Feito isso, vamos executar o comando a seguir no diretório de trabalho do projeto:

dotnet new blazorhosted — name Kanban

Este comando irá criar a mesma estrutura com os 3 projetos em uma solução, como fizemos na parte 1 com o Visual Studio. O argumento fornecido para o parâmetro —name irá dar nome para solução e projetos.

Com isso, teremos a seguinte estrutura de diretórios criada, quando abrirmos no Visual Studio Code:

Estrutura da solução criada com o CLI do .NET Core, aberta no Visual Studio Code

Mas ainda tem uma tarefa a ser feita. Removam o arquivo global.json, pois por padrão, ele “trava” a versão do .NET Core na 2.1.300. Isto já tem uma issue aberta (1386) no projeto oficial do Blazor e deve ser disponibilizado nos próximos dias com a versão 0.6.0.

Outro detalhe importante! O CLI não gera o arquivo .gitignore. No repositório que compartilhei no início do artigo tem um exemplo de arquivo para ser utilizado. Basta fazer o download desse arquivo, clonem o repositório e comecem esta parte a partir da branch parte1 como base.

Com isso, podemos prosseguir com o artigo. Lembrando sempre que para executar o projeto “com um todo”, devem executar o comando dotnet run dentro do diretório Kanban.Server, pois ele fornece tanto as APIs como o client do Blazor, como expliquei na parte 1, certo?

Um último detalhe, não obrigatório, mas o repositório tem um arquivo de exemplo do Azure Pipelines (azure-pipelines.yml). No meu caso, sempre que um PR for aberto para minha branch master ou algo for alterado nela, o Azure Devops irá executar o Build da aplicação para validar se o código está correto.

Classes de Domínio

Vamos começar a criar nossas classes de domínio no projeto Shared. Abaixo temos o código de cada uma delas. Vamos criar elas dentro de um diretório chamado Domain, que vamos criar no projeto Shared.

Notem que todas as classes possuem suas propriedades com setters privados e um construtor para “preencher” estas propriedades. Com isso vamos trabalhar com objetos imutáveis, onde apenas métodos de negócio irão poder gerar novos objetos com as modificações que precisamos. Vamos ver estes métodos quando começarmos a implementar nossa lógica de negócios.

Artifact

ArtifactAttachment

ArtifactStatus

ArtifactType

Iteration

Project

Team

User

Para finalizar esta parte sem estender muito o artigo, vamos configurar agora uma classe de contexto do Entity Framework Core para podermos trabalhar com nossos objetos.

Criando o contexto do Entity Framework Core

Notem que não utilizamos nenhuma anotação do EF Core nas classes, de modo que elas são puras, sem referências a frameworks, e podem ser utilizadas sem problemas no projeto client do Blazor. Vamos configurar nosso mapeamento com o banco de dados na classe de contexto do EF, utilizando a API fluente dele.

Primeiramente, vamos criar um novo projeto, chamado Kanban.Infra.Database, onde vamos configurar o Entity Framework e repositórios.

Para isto, no diretório onde encontra-se o arquivo Kanban.sln, execute o comando abaixo:

dotnet new classlib — name Kanban.Infra.Database

Podemos remover o arquivo “Class1.cs” que já vem no projeto.

E em seguida, acesse o diretório deste novo projeto criado e use o comando abaixo para referenciar o projeto Kanban.Shared:

cd Kanban.Infra.Database
dotnet add Kanban.Infra.Database.csproj reference ..\Kanban.Shared\Kanban.Shared.csproj

E finalmente, voltando para o diretório do arquivo de solução, o comando abaixo para incluir o projeto Kanban.Infra.Database na solução:

dotnet sln add Kanban.Infra.Database\Kanban.Infra.Database.csproj

Feito tudo isso, vamos criar no projeto Kanban.Infra.Database, um diretório chamado Contexts, e dentro dele uma classe chamada KanbanContext. Antes de implementarmos nossa classe de contexto, precisamos adicionar o Entity Framework ao projeto. Para isto, dentro do diretório do projeto Kanban.Infra.Database, vamos executar o comando abaixo:

dotnet add package Microsoft.EntityFrameworkCore.SqlServer

Notem que não é mais necessário adicionar o CLI do EF core nem o pacote Design, pois hoje eles já fazem parte do CLI do .NET Core, lembrando que a partir da versão 2.1.

Agora, vamos configurar nossa classe de Contexto. Para começar, vamos fazer ela estender a classe DbContext, e criar propriedades do tipo DbSet<T> para cada classe de domínio que criamos no projeto Shared, sendo T cada uma destas classes. Vamos codificar o construtor para receber as configurações de banco de dados através de um parâmetro do tipo DbContextOptions.

Teremos o seguinte resultado após esta primeira parte de codificação:

Agora, precisamos mapear nossas classes através da API fluente do EF Core. Não vou entrar em detalhes dela, pois não é o foco do artigo. Para quem tiver dúvidas ou quiser aprender um pouco mais sobre isto, segue o link da documentação oficial do EF Core. No menu lateral, temos as demais tarefas que podem ser feitas com a API fluente, como chave primária, relacionamentos, índices, etc.

Documentação EF Core: https://bit.ly/2yetwJJ

Para configurar o mapeamento de cada classe de domínio, vamos fazer isso sobrescrevendo o método OnModelCreating, que fornece um parâmetro do tipo ModelBuilder, que vamos utilizar para configurar cada classe de domínio. A assinatura do método é:

protected override void OnModelCreating(ModelBuilder modelBuilder)

Fazendo o mapeamento conforme a documentação da API fluente, temos o resultado abaixo. Notem que nem todas as classes tiveram o mapeamento de navegação, aquela propriedade do tipo List<EntidadeComMuitos>, pois só fiz nas classes que achei necessário por funcionalidade do sistema.

Camada de Repositórios

Vamos agora criar nossos repositórios. Por agora, vamos apenas criar a classe base, sendo um Repositório genérico e uma classe para cada Domínio, que apenas vão estender a classe base. Conforme avançarmos com as funcionalidades, vamos implementar métodos mais específicos em cada repositório, assim também não estendemos muito o artigo. Vamos antes criar um diretório Repositories, para colocar todos os repositórios.

A classe base dos repositórios, servindo de repositório genérico é mostrada abaixo. Note que é uma classe abstrata, forçando que cada Domínio precise ter sua própria classe de repositório implementada, que estende o repositório genérico, facilitando a identificação e injeção de dependência depois. Nomearemos nossa classe como GenericRepository, e esta será definida conforme uma interface, a IGenericRepository.

Nossa classe possui um parâmetro genérico T, que é representado por uma classe. Ao implementar cada um dos repositórios concretos, iremos informar qual domínio será utilizado. Abaixo temos uma interface e uma implementação de repositório como exemplo. Os demais encontram-se na branch parte2 do repositório.

Concluindo a parte 2

Por agora, vamos encerrar por aqui para não estender demais o artigo. O conteúdo que fizemos até aqui está disponível no repositório do Github, branch parte2.

Na próxima parte, vamos finalizar a configuração estrutural do projeto, criando nosso projeto para a camada de aplicação e criar as migrações do projeto de banco de dados, onde precisaremos fazer referência pelo projeto da API com as configurações de injeção de dependência e conexão ao banco de dados, para que o EF Core possa configurar as migrações. Vamos também já criar alguns dos controllers da API.

Irei lançar a parte 3 ainda esta semana, para finalizarmos a estrutura e começarmos a colocar a mão na massa com o Blazor.

Novamente, agradeço a todos que me acompanham aqui no Medium e aguardo feedback de vocês.

Um abraço!