Implementando CQRS com .NET 6 e MediatR

Lauan Guermandi
4 min readMay 31, 2022

--

Introdução

CQRS é um padrão arquitetural com foco em separar leitura a da escrita, onde alterações de dados são realizadas pelos Commands, e leitura de dados são realizadas pelas Queries.

Quando se utiliza CQRS, temos que ter ciência de que iremos trabalhar com a consistência eventual de nossos dados, já que iremos possuir uma base de dados para leitura e outra para escrita. Eventualmente as duas bases de dados estarão dessincronizadas.

Command e Query Stack

Como podemos ver no diagrama anterior, a partir de uma interação com o usuário, é gerado um command. Esse command provoca uma alteração no estado de nossa base de dados de escrita, e então gera um event. A response e recebida pela UI, e de forma assíncrona, o nosso event é processado, atualizando os dados de nossa base de leitura. Então podemos utilizar queries para consulta de dados na base de leitura.

Teorema CAP

Consistência: É desejável que seus dados sejam consistentes. No CQRS, trabalhamos com a consistência eventual dos dados, já que nem sempre as duas bases de dados(escrita e leitura), estão atualizadas.

Disponibilidade: Um dados, por mais que ele não esteja na sua versão mais recente, ele deve ser entregue.

Tolerância a falhas: Significa que quando uma parte a sua aplicação parar de funcionar, o resto deve continuar funcionando.

Dessas opções, você só pode escolher duas, ou seja, se você quer uma aplicação com consistência, e disponibilidade, ela não vai ser tolerante a falhas, e assim segue.

Ter as 3 opções é impossível.

Quando escolhemos o CQRS, temos disponibilidade e tolerância a falhas, assim a nossa consistência é eventual.

Preparando aplicação

Primeiro vamos subir um banco SQL Server utilizando o seguinte docker-compose:

E executando o comando:

docker-compose up -d

Agora vamos criar um projeto com o template de webapi:

dotnet new sln -n Products
dotnet new webapi -n Products.Api
dotnet sln add .\Products.Api

Pronto. O primeiro passo da implementação se definir as entidades e criar contextos de escrita e leitura.

Vamos trabalhar com uma entidade produto para este exemplo.

Agora criamos nossos contextos.

Então configuramos nossas strings de conexão:

E utilizando os seguintes comandos, iremos gerar nossa estrutura de banco de dados:

dotnet ef migrations add InitialMigration --context ProductWriteContextdotnet ef migrations add InitialMigration --context ProductReadContextdotnet ef database update --context ProductWriteContext
dotnet ef database update --context ProductReadContext

Com nossa estrutura definida, vamos criar uma repositório para realizar as operações no banco de dados:

E sua configuração:

builder.Services.AddScoped<IProductRepository, ProductRepository>();

Com nossa estrutura preparada, já podemos começar a implementação referente ao CQRS.

Implementando CQRS

Vamos criar um command que irá adicionar um produto.

Primeiro criamos o modelo de dados que o command irá receber:

E o seu executor(handler):

O modelo deve implementar a interface IRequest, com o tipo de retorno do command, que é bool.

O executor deve implementar a interface IRequestHandler, com o tipo do command, que é AddProductCommand, e o tipo de retorno que é bool.

Para configurar a referência do command ao seu handler, utilizamos a seguinte linha:

builder.Services.AddMediatR(typeof(AddProductCommand).GetTypeInfo().Assembly);

E para operações de consulta, vamos criar nosso serviço de queries:

Pronto! Agora vamos criar um controller para executar nossas operações:

Agora vamos testar:

--

--