DEV Community

Clean Architecture na Prática com CQRS e MediatR em .NET

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 │
└──────────────────┘
Enter fullscreen mode Exit fullscreen mode

🔄 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
Enter fullscreen mode Exit fullscreen mode

Configuração no ASP.NET Core

No arquivo Program.cs:

builder.Services.AddMediatR(cfg =>
    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
Enter fullscreen mode Exit fullscreen mode

🛠️ Exemplo Prático

1. Definindo o Command

public class CriarPedidoCommand : IRequest<Guid>
{
    public string Produto { get; set; }
    public int Quantidade { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

3. Definindo a Query

public class ObterPedidoQuery : IRequest<Pedido>
{
    public Guid Id { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ 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


🤝 Conecte-se Comigo

Top comments (0)