ASP.NET Core - Implementando Onion Architecture com CQRS - III
Hoje vamos realizar a implementação da Onion Architecture em uma aplicação ASP .NET Core aplicando o CQRS. |
Continuando a segunda parte do artigo vamos agora implementar os comandos e consultas segundo o CRQS usando o MediatR.
Implementando o CQRS com MediatR
O acrônimo CQRS significa - Command Query Responsibility Segregation - e é um padrão de projeto que separa as operações de leitura e escrita da base de dados em dois modelos: Queries e Commands.
Os Commands são responsáveis pelas ações que realizam alguma alteração na base de dados e em geral são operações assíncronas sem retorno.
As Queries são responsáveis pelas consultas, e retornam objetos DTOs (Data Transfer Object).
O MediatR é uma biblioteca aberta criada por Jimmy Bogard , e, o seu objetivo é facilitar a implementação do Padrão Mediator em aplicações .NET. Com ela não precisamos nos preocupar com a criação da classe mediadora, pois já são fornecidas interfaces que facilitam a implementação do fluxo de comunicação entre os objetos.
A criação de Commands usando o MediatR é composta por dois objetos:
Veja o meu artigo sobre o padrão MediatR : Usando o padrão Mediator com MediatR (CQRS)
Vamos realizar esta implementação no projeto Application onde criamos a pasta CQRS, e, agora dentro desta pasta, vamos criar duas pastas:
1- Commands
Na pasta Commands crie a classe CreateAlunoCommand
using Domain.Entities; using Domain.Interfaces; using MediatR; using System; using System.Threading; using System.Threading.Tasks; namespace Application.CQRS.Commands public class CreateAlunoCommandHandler : IRequestHandler<CreateAlunoCommand, Aluno> if (aluno == null) |
Observe que nesta implementação usamos o recurso das classes internas ou inner class para implementar o Handler em CreateAlunoCommandHandler, onde no seu construtor injetamos uma instância do Repositório que criamos no projeto Infrastructure, e, implementamos o método Handle que cria um novo aluno.
A seguir vamos criar a classe UpdateAlunoCommand :
using Domain.Entities; using Domain.Interfaces; using MediatR; using System; using System.Threading; using System.Threading.Tasks; namespace Application.CQRS.Commands public class UpdateAlunoCommandHandler : IRequestHandler<UpdateAlunoCommand, Aluno> public async Task<Aluno> Handle(UpdateAlunoCommand request, if (aluno == null) return await _alunoRepository.UpdateAsync(aluno); |
Esta implementação segue a mesma lógica do comando anterior. Aqui estamos atualizando os dados de um aluno e para isso usamos o método Update definido no Domain.
Para concluir crie a classe RemoveAlunoCommand :
using Domain.Entities; using Domain.Interfaces; using MediatR; using System; using System.Threading; using System.Threading.Tasks; namespace Application.CQRS.Commands public async Task<Aluno> Handle(RemoveAlunoCommand request, if (aluno == null) |
Aqui estamos removendo um aluno pelo seu Id.
1- Queries
Na pasta Queries vamos criar a classe GetAlunosQuery que vai retornar todos os alunos :
using Domain.Entities; using Domain.Interfaces; using MediatR; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Application.CQRS.Queries |
A agora crie a classe GetAlunoIdQuery que vai retornar um aluno pelo seu Id:
using Domain.Entities; using Domain.Interfaces; using MediatR; using System.Threading; using System.Threading.Tasks;
namespace Application.CQRS.Queries public async Task<Aluno> Handle(GetAlunoIdQuery request, CancellationToken cancellationToken) |
Dessa forma já implementamos as consultas e os comandos seguindo o padrão CQRS e usamos o MediatR.
Agora podemos implementar a classe AlunoService na pasta Services:
using Application.CQRS.Commands; using Application.CQRS.Queries; using Application.DTOs; using Application.Interfaces; using AutoMapper; using MediatR; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Application.Services public AlunoService(IMapper mapper, IMediator mediator) if (alunosQuery == null) var result = await _mediator.Send(alunosQuery); return _mapper.Map<IEnumerable<AlunoDto>>(result); if (alunoByIdQuery == null) var result = await _mediator.Send(alunoByIdQuery); return _mapper.Map<AlunoDto>(result); public async Task CreateAsync(AlunoDto alunoDto, CancellationToken cancellationToken = default) if (alunoRemoveCommand == null) await _mediator.Send(alunoRemoveCommand); |
Aqui injetamos o AutoMapper e o MediatR no construtor da classe e usando o MediatR estamos encaminhando o Request para o respectivo comando ou consulta.
No serviço estamos usando os comandos e consultas implementadas na pasta CQRS do projeto.
Assim temos os comandos e consultas implementadas e também o serviço, e, podemos partir para a definição da camada de apresentação.
Na próxima parte do artigo iremos implementar a Web API ApiAlunos na camada Presentation.
"Ai dos que
ao mal chamam bem, e ao bem mal; que fazem das trevas luz, e da luz trevas;
e fazem do amargo doce, e do doce amargo!"
Isaías 5:20
Referências:
C# - Lendo e escrevendo em arquivos textos e binários
C# - Entendo o I/O na plataforma .NET
C# - Fluxo assíncrono ou async streams