Clean Architecture é um padrão arquitetural que visa promover a separação de responsabilidades, facilitando a manutenção e evolução do sistema. Quando combinado com CQRS (Command Query Responsibility Segregation) e a biblioteca MediatR, é possível criar aplicações escaláveis, testáveis e de fácil manutenção em .NET.
🧭 O que é Clean Architecture?
Clean Architecture propõe uma estrutura onde as dependências fluem de fora para dentro, garantindo que o núcleo da aplicação (domínio) não dependa de detalhes de implementação, como frameworks ou bancos de dados. A estrutura típica é:
┌──────────────────┐ │ Entities │ └──────────────────┘ ▲ ┌──────────────────┐ │ Use Cases / Application │ └──────────────────┘ ▲ ┌──────────────────┐ │ Interface Adapters │ └──────────────────┘ ▲ ┌──────────────────┐ │ Frameworks & Drivers │ └──────────────────┘
🔄 O que é CQRS?
CQRS é um padrão que separa as operações de leitura (Query) das de escrita (Command). Isso permite otimizar cada operação de forma independente e melhora a escalabilidade e segurança da aplicação.
- Command: Representa uma ação que altera o estado do sistema.
- Query: Representa uma consulta que retorna dados sem modificá-los.
🧩 Integrando MediatR
MediatR é uma biblioteca que implementa o padrão Mediator, facilitando a comunicação entre componentes sem que eles se conheçam diretamente. Ela é ideal para implementar CQRS em .NET.
Instalação
Install-Package MediatR Install-Package MediatR.Extensions.Microsoft.DependencyInjection
Configuração no ASP.NET Core
No arquivo Program.cs
:
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
🛠️ Exemplo Prático
1. Definindo o Command
public class CriarPedidoCommand : IRequest<Guid> { public string Produto { get; set; } public int Quantidade { get; set; } }
2. Criando o Command Handler
public class CriarPedidoHandler : IRequestHandler<CriarPedidoCommand, Guid> { private readonly IPedidoRepository _pedidoRepository; public CriarPedidoHandler(IPedidoRepository pedidoRepository) { _pedidoRepository = pedidoRepository; } public async Task<Guid> Handle(CriarPedidoCommand request, CancellationToken cancellationToken) { var pedido = new Pedido(request.Produto, request.Quantidade); await _pedidoRepository.AdicionarAsync(pedido); return pedido.Id; } }
3. Definindo a Query
public class ObterPedidoQuery : IRequest<Pedido> { public Guid Id { get; set; } }
4. Criando o Query Handler
public class ObterPedidoHandler : IRequestHandler<ObterPedidoQuery, Pedido> { private readonly IPedidoRepository _pedidoRepository; public ObterPedidoHandler(IPedidoRepository pedidoRepository) { _pedidoRepository = pedidoRepository; } public async Task<Pedido> Handle(ObterPedidoQuery request, CancellationToken cancellationToken) { return await _pedidoRepository.ObterPorIdAsync(request.Id); } }
5. Controlador ASP.NET Core
[ApiController] [Route("api/[controller]")] public class PedidosController : ControllerBase { private readonly IMediator _mediator; public PedidosController(IMediator mediator) { _mediator = mediator; } [HttpPost] public async Task<IActionResult> CriarPedido([FromBody] CriarPedidoCommand command) { var pedidoId = await _mediator.Send(command); return CreatedAtAction(nameof(ObterPedido), new { id = pedidoId }, null); } [HttpGet("{id}")] public async Task<IActionResult> ObterPedido(Guid id) { var pedido = await _mediator.Send(new ObterPedidoQuery { Id = id }); if (pedido == null) return NotFound(); return Ok(pedido); } }
✅ Vantagens da Abordagem
- Desacoplamento: Com MediatR, os componentes não se comunicam diretamente, facilitando a manutenção e evolução do sistema.
- Testabilidade: Comandos e consultas podem ser testados isoladamente.
- Escalabilidade: Permite otimizar operações de leitura e escrita de forma independente.
- Organização: A separação clara entre comandos, consultas e manipuladores facilita a compreensão do sistema.
🔗 Recursos Adicionais
- Implementando CQRS com MediatR e ASP.NET Core
- Integrando CQRS e Mediator em .NET com MediatR
- MediatR e Arquitetura Limpa em projetos .NET
Top comments (0)