Hoje vamos continuar a apresentar os conceitos e princípios que nos ajudam a implementar uma arquitetura aderente aos princípios da Clean Architecture. |
Continuando o artigo anterior vamos prosseguir definindo os projetos Domain, Application e Infra.
Definindo o Domain e o Contexto
Vamos criar um projeto do tipo Class Library (.NET Core) em nossa solução CleanArch.
Para isso clique com o botão do mouse sobre a solução e selecione Add-> New Project;
Escolha o template Classe Library(.NET Core) a seguir informe o nome CleanArch.Domain e clique em Create;
No projeto criado vamos remover o arquivo Class1.cs e alterar o <TargetFramework> do arquivo de projeto para net5.0:
Vamos criar uma pasta chamada Entities neste projeto e nesta pasta criar a classe que representa o nosso modelo de domínio e que a titulo de exemplo será a classe Product:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
}
|
A classe Product foi definida com apenas 4 propriedades e sem nenhum comportamento. É uma classe anêmica que em um projeto mais aderente à Clean Architecture deveria ser mais expressiva.
Como neste artigo eu quero mostrar basicamente como criar um projeto usando a estrutura de um projeto aderente à Clean Architecture, para deixar o exemplo mais simples, vou trabalhar com classes anêmicas, mas isso em um projeto de produção não seria feito assim, deveríamos definir também os comportamentos e usar apenas o modificador get.
Vamos criar agora um novo arquivo de contexto de forma a podermos atualizar o banco de dados usado pela aplicação com este novo modelo de domínio.
Para isso vamos criar um novo projeto do tipo Class Library(.NET Core) na solução chamado CleanArch.Infra.Data da mesma forma que criamos o projeto CleanArch.Domain. Lembrando de alterar o TargetFramework para net5.0.
Após criar o projeto vamos incluir uma referência neste projeto para o projeto CleanArch.Domain via menu suspenso Add->Project Reference e aproveitar e incluir uma referência no projeto CleanArch.UI.MVC ao projeto CleanArch.Domain.
Agora no CleanArch.Infra.Data vamos criar uma pasta chamada Context e criar nesta pasta a classe ProductDbContext que representa o arquivo de contexto para o nosso domínio Product.
Mas antes precisamos incluir no projeto as referências ao Entity Framework Core:
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
Após isso podemos criar a classe de contexto:
public class ProductDbContext : DbContext
{
public ProductDbContext(DbContextOptions options) : base(options)
{ }
public DbSet<Product> Products { get; set; }
}
|
A seguir vamos configurar este novo Contexto no arquivo Startup do projeto CleanArch.UI.MVC.
Inclua o trecho de código abaixo no método ConfigureServices da classe Startup:
... services.AddDbContext<ProductDbContext>(options => options.UseSqlServer( Configuration.GetConnectionString("ProductConnection"))); ... |
E agora precisamos definir no arquivo appsettings do projeto a string de conexão definida como ProductConnection :
Com isso podemos aplicar o Migrations usando os comandos:
Após gerar o arquivo de script XXXXXX_InicialProducts na pasta Migrations do projeto e após o comando update-database teremos o banco de dados ProductDB e a tabela Products criadas no SQL Server.
Aqui podemos aproveitar e incluir alguns dados para teste na tabela Products.
Podemos fazer isso usando uma instrução SQL Insert Into no SQL Server Management Studio:
Executando esta consulta e abrindo a tabela Products veremos os dados inseridos:
Vamos agora criar o projeto Application.
Criando o projeto Application
Vamos criar o projeto do tipo Class Library (.NET Core) chamado CleanArch.Application na solução da mesma forma que fizemos anteriormente, alterando o TargetFramework para net 5.0.
Após criar o projeto vamos incluir uma referência neste projeto para o projeto CleanArch.Domain via menu suspenso Add->Project Reference.
Neste projeto vamos definir os serviços, as interfaces e as view models. Assim vamos criar 3 pastas neste projeto:
Vamos começar definindo as ViewModels.
Uma ViewModel representa os dados que você deseja exibir em sua view ou página, seja usado para texto estático ou para valores de entrada (como caixas de texto e listas suspensas) que podem ser adicionados ao banco de dados. É algo diferente do seu modelo de domínio. É um modelo para a a view. Em outras palavras, ele cria uma máscara para os modelos de domínio.
Vamos criar a classe ProductViewModel na pasta ViewModels e definir apenas a propriedade para obter uma lista de produtos do banco de dados conforme o código abaixo:
using CleanArch.Domain.Entities;
using System.Collections.Generic;
namespace CleanArch.Application.ViewModels
{
public class ProductViewModel
{
public IEnumerable<Product> Produtos { get; set; }
}
}
|
A seguir na pasta Interfaces vamos criar a interface IProductService que vai atuar como um contrato para a funcionalidade que estamos implementando.
using CleanArch.Application.ViewModels;
namespace CleanArch.Application.Interfaces
{
public interface IProductService
{
ProductViewModel GetProdutcs();
}
}
|
Quando o método
GetProducts() for implementado, ele retornará uma
lista de produtos, e ele só conhece o ViewModel,
não sabe nada do modelo de domínio Product, então
estamos abstraindo a entidade central fazendo isso, ao invés de ter tudo em um
só lugar.
Antes de definir a implementação para IProductService,
temos que definir uma maneira de obter os dados do banco de dados. Para fazer
isso, podemos usar o Entity Framework diretamente, mas vamos usar o padrão
Repository para separar a lógica do negócio e as
camadas de acesso a dados em nosso aplicativo.
Então vamos criar a interface do repositório no projeto Domain.
Crie uma pasta chamada Interfaces no projeto Domain e a seguir crie a interface IProducttRepository nesta pasta.
using CleanArch.Domain.Entities;
using System.Collections.Generic;
namespace CleanArch.Domain.Interfaces
{
public interface IProductRepository
{
IEnumerable<Product> GetProducts();
}
}
|
Neste momento se o
projeto MVC, ou a camada de apresentação (que não tem nenhuma ideia sobre a
entidade de domínio Product) solicitar uma
lista de livros, ela vai precisar falar com
ProductService (que nós não implementamos ainda, usando
IProductService), e ProductService precisa
obtê-lo a partir do repositório ProductRepository (que
também não implementamos ainda, usando IProductRepository)
Então, vamos implementá-los. Começando com
ProductRepository.
Obs: O padrão de projeto Repository medeia entre o domínio e as camadas de mapeamento de dados usando uma interface semelhante a uma coleção para acessar os objetos do domínio. Em outras palavras, podemos dizer que o padrão Repositório atua como um intermediário ou camada intermediária entre o restante do aplicativo e a lógica de acesso aos dados.
Vamos implementar a classe concreta ProductRepository que define o padrão Repository no projeto CleanArch.Infra.Data.
Crie uma pasta Repositories neste projeto e a seguir crie a classe ProductRepository com o código a seguir:
Note que injetamos uma instância do contexto para a seguir ter acesso a entidade Products que esta mapeada para a tabela Products.
Agora podemos implementar o serviço ProductService no projeto Application.
Para isso crie a classe ProductService na pasta Services do projeto e inclua o código abaixo:
Observe que injetamos uma instância da nossa implementação do padrão Repository para acessar o método GetProducts() a partir do Repositório.
A estrutura atual do nosso projeto é vista na figura :
E as referências entre os projetos esta definida assim:
Agora precisamos tratar da implementação do projeto CleanArch.Infra.IoC, que nos ajudará a conter e separar as dependências.
Faremos isso na próxima parte do artigo.
"Se esperamos em Cristo só nesta vida, somos os mais
miseráveis de todos os homens."
1 Coríntios 15:19
Referências:
ASP .NET Core - Iniciando com o Blazor
ASP .NET Core - CRUD usando Blazor e Entity ..
Blazor - O novo framework SPA da Microsoft
Visual Studio Code - Suporte ao desenvolvimento Blazor
ASP .NET - Arquitetura em camadas
NET - Considerações sobre arquitetura e ..
NET - Compreendendo a arquitetura em ...
NET - A arquitetura em cebola (Onion Architecture)