ASP .NET Core 5 - Implementando CQRS com Mediator - II
Neste artigo vamos continuar a implementação do CQRS - Command Query Responsibility Segregation usando o padrão Mediator.(Mediatr) |
Continuando o artigo anterior vamos partir para realizar a implementação do CQRS usando o MediatR.
CQRS - Implementação com os comandos e as consultas
Vamos agora iniciar a implementação do CQRS no projeto Application definindo os Commands e as Queries e vamos precisar instalar a biblioteca MediatR.
Para isso podemos usar a janela do Package Manger Console e digitar o comando:
A seguir vamos criar as seguintes pastas no projeto Application :
A criação de Commands usando o MediatR é composta por dois objetos:
Na implementação podemos criar duas classes distintas ou podemos usar o recurso das classes internas do C# e criar as duas classes em um único arquivo. Neste exemplo eu vou criar as duas classes em um único arquivo como classes internas.
Na pasta Commands vamos definir o primeiro Command criando a classe CreateCustomerCommand que vai adicionar um novo cliente:
using DemoMediator.Domain.Entities;
using DemoMediator.Domain.Interfaces;
using MediatR;
using System.Threading;
using System.Threading.Tasks;
namespace DemoMediator.Application.Services.Commands
{
public class CreateCustomerCommand : IRequest<int>
{
public string Name { get; set; }
public string Email { get; set; }
public class CreateProductCommandHandler : IRequestHandler<CreateCustomerCommand, int>
{
private readonly ICustomerRepository _context;
private readonly IMediator _mediator;
public CreateProductCommandHandler(ICustomerRepository context, IMediator mediator)
{
_context = context;
_mediator = mediator;
}
public async Task<int> Handle(CreateCustomerCommand command,
CancellationToken cancellationToken)
{
var customer = new Customer();
customer.Name = command.Name;
customer.Email = command.Email;
_context.Add(customer);
return customer.Id;
}
}
}
}
|
Vamos entender o
código:
Primeiro, criamos a classe Command -
CreateCustomCommand - e implementamos
IRequest<int> onde estamos indicando que vamos
retornar um inteiro. Esse recurso vem da biblioteca MediatR.
A classe possui duas
propriedades Name e Email que representa os dados que estamos criando.
Em seguida, criamos a classe interna
CreateProductCommandHandler
que
herda da classe RequestHandler<Command, int>
onde estamos indicando qual Comando será tratado e o retorno esperado.
A seguir injetamos o serviço do repositório definido por _context e a instância do Mediator (_mediator) no construtor, depois implementamos o método Handle (Command request), adicionando o valor à nossa fonte de dados usando a instância do repositório.
Essa lógica vai ser seguida para implementar os outros dois comandos que iremos criar:
a- UpdateCustomerCommand - que atualiza um cliente existente
using DemoMediator.Domain.Interfaces;
using MediatR;
using System.Threading;
using System.Threading.Tasks;
namespace DemoMediator.Application.Services.Commands
{
public class UpdateCustomerCommand : IRequest<int>
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public class UpdateProductCommandHandler : IRequestHandler<UpdateCustomerCommand, int>
{
private readonly ICustomerRepository _context;
private readonly IMediator _mediator;
public UpdateProductCommandHandler(ICustomerRepository context, IMediator mediator)
{
_context = context;
_mediator = mediator;
}
public async Task<int> Handle(UpdateCustomerCommand command, CancellationToken cancellationToken)
{
var customer = await _context.GetById(command.Id);
if (customer == null) return default;
customer.Name = command.Name;
customer.Email = command.Email;
_context.Update(customer);
return customer.Id;
}
}
}
}
}
|
b- DeleteCustomerByIdCommand - que exclui um cliente existente
using DemoMediator.Domain.Interfaces;
using MediatR;
using System.Threading;
using System.Threading.Tasks;
namespace DemoMediator.Application.Services.Commands
{
public class DeleteCustomerByIdCommand : IRequest<int>
{
public int Id { get; set; }
public class DeleteProductByIdCommandHandler : IRequestHandler<DeleteCustomerByIdCommand, int>
{
private readonly ICustomerRepository _context;
private readonly IMediator _mediator;
public DeleteProductByIdCommandHandler(ICustomerRepository context, IMediator mediator)
{
_context = context;
_mediator = mediator;
}
public async Task<int> Handle(DeleteCustomerByIdCommand command, CancellationToken cancellationToken)
{
var customer = await _context.GetById(command.Id);
if (customer == null) return default;
_context.Remove(customer);
return customer.Id;
}
}
}
}
|
Já criamos os Commands vamos criar a seguir as Queries.
Vamos agora criar as consultas na pasta Queries e vamos fazer isso criando classes internas.
A primeira consulta - GetAllCustomersQuery - irá retornar todos os clientes :
using DemoMediator.Domain.Entities;
using DemoMediator.Domain.Interfaces;
using MediatR;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace DemoMediator.Application.Services.Queries
{
public class GetAllCustomersQuery : IRequest<IEnumerable<Customer>>
{
public class GetAllCustomersQueryHandler : IRequestHandler<GetAllCustomersQuery,
IEnumerable<Customer>>
{
private readonly ICustomerRepository _context;
private readonly IMediator _mediator;
public GetAllCustomersQueryHandler(ICustomerRepository context, IMediator mediator)
{
_context = context;
_mediator = mediator;
}
public async Task<IEnumerable<Customer>> Handle(GetAllCustomersQuery query,
CancellationToken cancellationToken)
{
var customerList = await _context.GetAll();
if (customer == null) return default;
return customerList;
}
}
}
}
|
Vamos entender o código :
Primeiro, criamos
uma classe interna ou inner class chamada
GetAllCustomersQuery
,
que implementa IRequest<IEnumerable<Customer>>. Isso
significa que nosso Request vai retornar uma
lista clientes.
Em seguida, criamos outra classe interna chamada
GetAllCustomersQueryHandler
, que herda de
IRequestHandler<GetAllCustomersQuery,IEnumerable<Customer>>. Isso significa que essa classe
tratará a Query ou Consulta, neste caso, retornando a lista de
clientes.
No construtor desta classe injetamos uma instância do nosso repositório e do mediator e a seguir implementamos um único método chamado Handle, que retorna os valores de nosso repositório.
A outra consulta - GetCustomerByIdQuery - vai retornar um cliente pelo seu id, e vai seguir a mesma abordagem:
using DemoMediator.Domain.Entities;
using DemoMediator.Domain.Interfaces;
using MediatR;
using System.Threading;
using System.Threading.Tasks;
namespace DemoMediator.Application.Services.Queries
{
public class GetCustomerByIdQuery : IRequest<Customer>
{
public int Id { get; set; }
public class GetProductByIdQueryHandler : IRequestHandler<GetCustomerByIdQuery, Customer>
{
private readonly ICustomerRepository _context;
private readonly IMediator _mediator;
public GetProductByIdQueryHandler(ICustomerRepository context, IMediator mediator)
{
_context = context;
_mediator = mediator;
}
public async Task<Customer> Handle(GetCustomerByIdQuery query, CancellationToken cancellationToken)
{
var customer = await _context.GetById(query.Id);
if (customer == null) return default;
return customer;
}
}
}
}
|
Com isso temos os comandos e as consultas criadas usando a biblioteca MediatR e podemos agora continuar implementando o nosso controlador CustomersController para testar os comandos e consultas.
Na janela Solution Explorer veremos a seguinte estrutura e conteúdo para o projeto Application:
Na próxima parte do artigo vamos continuar implementando o controlador CustomersController.
Não se turbe o
vosso coração; credes em Deus, crede também em mim.
Na casa de meu Pai há muitas moradas. Se assim não fora, eu vo-lo teria dito.
Pois vou preparar-vos lugar.
João 14:1,2
Referências:
ASP .NET Core - Implementando a segurança com ...
ASP.NET Core MVC - Criando um Dashboard ..
C# - Gerando QRCode - Macoratti
ASP .NET - Gerando QRCode com a API do Google