Camada de Infraestrutura

Arquitetura Limpa

Criação do Projeto de Infraestrutura

O projeto de infraestrutura é criado como uma biblioteca de classes independente:

dotnet new classlib -o CleanArchitectureStore.Infrastructure
dotnet sln add .\CleanArchitectureStore.Infrastructure\

Este projeto constitui a camada mais externa na Arquitetura Limpa, responsável por implementações concretas de detalhes técnicos como persistência de dados, comunicação externa e integrações com sistemas de terceiros.

Configuração de Dependências

Referência ao Projeto de Domínio

O projeto de infraestrutura referencia o domínio para acessar as interfaces definidas:

dotnet add reference ..\CleanArchitectureStore.Domain\

Esta referência estabelece a direção correta de dependência: a infraestrutura depende do domínio, implementando suas abstrações.

Instalação do Entity Framework Core

O pacote necessário para integração com SQL Server é adicionado:

dotnet add package Microsoft.EntityFrameworkCore.SqlServer

O arquivo de projeto resultante reflete estas dependências:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.1" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\CleanArchitectureStore.Domain\CleanArchitectureStore.Domain.csproj" />
  </ItemGroup>
</Project>

Configuração de Mapeamento de Entidades

Estrutura de Diretórios para Mapeamentos

A organização de mapeamentos é estabelecida no diretório Data/Mappings/, separando claramente a configuração de persistência da lógica de domínio.

Classe de Mapeamento ProductMap

A configuração de mapeamento para a entidade Product é implementada:

Análise da configuração de mapeamento:

  1. ToTable("Product"): Especifica o nome da tabela no banco de dados, permitindo desacoplamento entre o nome da entidade e o nome da tabela.

  2. HasKey(x => x.Id): Define Id como chave primária. Em sistemas que utilizam Guid, o Entity Framework Core normalmente configura automaticamente, mas a especificação explícita garante clareza.

  3. Configuração da propriedade Title:

    • .IsRequired(): Impede valores NULL no banco de dados, garantindo integridade referencial

    • .HasMaxLength(160): Define limite máximo para otimização de armazenamento e prevenção de erros

    • .HasColumnType("NVARCHAR"): Especifica o tipo de dados SQL Server, importante para collation e comparações

Implementação do Contexto de Dados

Classe AppDbContext

O contexto principal de dados é definido como uma especialização de DbContext:

Análise detalhada do AppDbContext:

  1. Construtor Primário: Utiliza a sintaxe de construtor primário do C# 12, recebendo DbContextOptions<AppDbContext> que contém configurações como connection string.

  2. Propriedade DbSet:

    • public DbSet<Product> Products { get; set; } = null!;

    • A inicialização com null! (null-forgiving operator) informa ao compilador que a propriedade será inicializada pelo Entity Framework Core, evitando warnings do Nullable Reference Types.

    • O operador ! afirma ao analisador que o valor nunca será null em tempo de execução.

  3. Método OnModelCreating:

    • modelBuilder.ApplyConfigurationsFromAssembly(typeof(DependencyInjection).Assembly);

    • Carrega automaticamente todas as classes que implementam IEntityTypeConfiguration<T> no assembly da infraestrutura.

    • typeof(DependencyInjection).Assembly obtém a referência ao assembly atual, independentemente de qual classe é utilizada como referência.

Alternativas para Obtenção do Assembly

A escolha de typeof(DependencyInjection).Assembly é arbitrária - qualquer classe definida no projeto de infraestrutura funcionará igualmente.

Implementação do Repositório Concreto

Estrutura de Diretórios para Repositórios

Os repositórios concretos são organizados no diretório Repositories/, separando as implementações das definições de interface no domínio.

Classe ProductRepository

A implementação concreta do repositório é definida:

Características da implementação:

  1. Herança da Interface do Domínio: IProductRepository é definido no projeto de domínio, mantendo o Princípio da Inversão de Dependência.

  2. Injeção via Construtor Primário: Recebe AppDbContext diretamente no construtor, simplificando a declaração.

  3. Implementação Concisa: Utiliza expressão-bodied member para método simples, mantendo legibilidade.

  4. Consulta Eficiente: FirstOrDefaultAsync é adequado para buscas por identificador único.

  5. Respeito ao CancellationToken: Propaga corretamente o token de cancelamento para operações assíncronas.

Configuração de Injeção de Dependência

Classe DependencyInjection na Infraestrutura

Uma classe estática é criada para encapsular a configuração de serviços de infraestrutura:

Análise da configuração:

  1. Método de Extensão: AddInfrastructure estende IServiceCollection, permitindo chamada fluente na configuração da API.

  2. Registro de Serviços:

    • services.AddTransient<IProductRepository, ProductRepository>();

    • Registra ProductRepository como implementação de IProductRepository

    • Escopo Transient: Nova instância criada a cada solicitação, adequado para serviços stateless

  3. Localização Centralizada: Todos os registros de serviços de infraestrutura são concentrados neste método.

Classe DependencyInjection na Aplicação

Similarmente, a camada de aplicação define sua configuração de dependências:

Configuração do MediatR:

  1. AddMediatR: Método de extensão fornecido pelo pacote MediatR.Extensions.Microsoft.DependencyInjection.

  2. Registro por Assembly:

    • RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly)

    • Escaneia automaticamente o assembly da aplicação para:

      • Commands/Queries que implementam IRequest<T>

      • Handlers que implementam IRequestHandler<TRequest, TResponse>

      • Behaviors (pipeline behaviors)

      • Pre/Post processors

  3. Configuração Flexível: O parâmetro configuration permite personalizações adicionais como:

    • Registro de behaviors de pipeline

    • Configuração de publicação de notificações

    • Personalização do lifetime scope dos handlers

Visualização da Estrutura da Solução

A solução completa apresenta a seguinte organização:

Princípios Arquiteturais Aplicados

Dependency Inversion Principle (DIP)

  1. Módulos de Alto Nível (Domínio): Define abstrações (IProductRepository)

  2. Módulos de Baixo Nível (Infraestrutura): Implementa concretizações (ProductRepository)

  3. Direção de Dependência: Infraestrutura → Domínio (correto na Clean Architecture)

Separation of Concerns

  1. Domínio: Regras de negócio e entidades

  2. Aplicação: Orquestração de casos de uso

  3. Infraestrutura: Detalhes técnicos de implementação

  4. Apresentação: Interface com usuário/externo

Testabilidade

  1. Domínio Testável: Sem dependências externas, testável isoladamente

  2. Aplicação Testável: Depende apenas de interfaces, facilmente simulável

  3. Infraestrutura Testável: Pode ser testada com banco de dados em memória

Próximas Etapas para a API

Com a infraestrutura configurada, os preparativos para a camada de apresentação incluem:

Configuração da API

  1. Criação do Projeto API: dotnet new webapi -o CleanArchitectureStore.Api

  2. Adição à Solução: dotnet sln add .\CleanArchitectureStore.Api\

  3. Referências Necessárias: Projetos Application e Infrastructure

Configuração de Serviços

No Program.cs da API:

Configuração do Banco de Dados

  1. Connection String: Configurada em appsettings.json

  2. Migrações: Gerenciadas via CLI do Entity Framework

  3. Health Checks: Monitoramento da conexão com banco

Implementação de Endpoints

Controllers ou endpoints minimal API que:

  1. Recebem requisições HTTP

  2. Mapeiam para Commands/Queries

  3. Invocam MediatR

  4. Transformam Results em respostas HTTP apropriadas

Esta estrutura completa da infraestrutura estabelece uma base sólida para a camada de apresentação, garantindo que todos os detalhes técnicos de persistência e integração estejam adequadamente encapsulados e desacoplados das regras de negócio centrais.

Atualizado