O Mediator é um padrão de projeto comportamental criado pelo GoF, que nos ajuda a garantir um baixo acoplamento entre os objetos de nossa aplicação.
Ele permite que um objeto se comunique com outros sem saber suas estruturas. Para isso, devemos definir um ponto central que irá encapsular como os objetos irão se comunicar uns com os outros.
Neste artigo veremos como podemos criar uma API ASP.Net Core que faz uso desse padrão de projeto usando a biblioteca MediatR.
- Não deixe de conferir um projeto de demonstração no qual faço uso do MediatR e que está no meu GitHub.
MediatR
O MediatR foi criado por Jimmy Bogard, o mesmo criador do famoso AutoMapper. Ele implementa o padrão de projeto Mediator de uma forma bem simples.
Para instalar em seu projeto execute o seguinte comando:
dotnet add package MediatR
Basicamente temos dois componentes principais chamados Request e Handler, que implementamos através das interfaces IRequest e IRequestHandler<TRequest>, respectivamente.
- Request: mensagem que será processada
- Handler: responsável por processar determinada(s) mensagem(s)
Não confunda o Request do MediatR com um request HTTP. Request é o nome usado pelo MediatR para descrever uma mensagem que será processada por um Handler.
Além disso, algumas literaturas usam o termo Command para descrever essas mensagens. Eu mesmo ainda uso esse termo de vez em quando.
public class OneWay : IRequest
{
}
public class OneWayHandler : IRequestHandler<OneWay>
{
public Task Handle(OneWay request, CancellationToken cancellationToken)
{
// processamento
}
}
- Veja que a implementação acima apenas executa determinada tarefa e não tem nenhum retorno.
Podemos ter um Request que devolverá uma resposta para quem o invocou. No caso, devemos implementar um Request que tem uma resposta associada à ele usando a interface IRequest<TResponse>.
public class Ping : IRequest<string>
{
}
public class PingHandler : IRequestHandler<Ping, string>
{
public Task<string> Handle(Ping request, CancellationToken cancellationToken)
{
return Task.FromResult("Pong");
}
}
Um Request normalmente contém propriedades que são usadas para fazer o input dos dados para os Handlers. Esses dois componentes não fazem nada sozinhos. Precisamos de um intermediador, que será responsável por receber um Request e invocar o Handler associado a ele.
Para isso, temos um componente chamado Mediator, que implementa a interface IMediator, por onde deveremos interagir com as demais classes.
- A classe Mediator já está implementada e não precisamos nos preocupar com ela.
Usando a interface IMediator, nossas classes não saberão quem ou quais componentes realizarão determinada ação. Apenas enviamos para o Mediator e ele se encarregará de chamar a classe que executará o que precisamos. Simples assim!
Com isso, temos um baixo acoplamento e fácil manutenção. Cada Handler normalmente irá tratar um único Request, e assim podemos ter classes menores e mais simples.
Entretanto, nada impede de você definir mais de um Request para um Handler. Basta implementar mais uma interface IRequestHandler e fazer a correta injeção de dependências para isso.
As primeiras versões do MediatR eram totalmente assíncronas, mas nas novas versões temos a possibilidade de omitir o CancelationToken, caso não seja necessário, ou ainda criar Handlers que são processados de forma síncrona.
Também podemos fazer a publicação de mensagens que devem ser processadas por vários Handlers simultaneamente. Esse recurso leva o nome de Notifications.
Além disso, o MediatR também tem um mecanismo para interceptar a execução de determinado Handler chamado Pipeline Behavior, que irei abordar em um próximo artigo.
Podemos perceber que o MediatR é bem completo, e é uma ferramenta poderosa que pode nos ajudar muito na criação de aplicações modernas, e pode ser usado em conjunto com padrões como o CQRS (Command Query Responsibility Segregation).
Para mais detalhes, não deixe de conferir a documentação oficial que está disponível no repositório do MediatR.
Usando Mediator em Controllers do ASP.Net Core
Gosto muito de usar o Mediator para manter minhas Controllers limpas. Basicamente elas recebem os requests HTTP e executam o Mediator. Normalmente já recebo o objeto de Request do MediatR como parâmetro das Actions em minhas Controllers. Dessa forma, o próprio ASP.Net fará o Model Binding apropriado para meu objeto de Request do MediatR.
[Route("api/[controller]")]
public class AccountsController : Controller
{
private readonly IMediator _mediator;
public AccountsController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost, AllowAnonymous, Route("login")]
public async Task<IActionResult> Authenticate([FromBody] AuthenticateUser command)
{
var response = await _mediator.Send(command);
if (response.Errors.Any())
{
return BadRequest(response.Errors);
}
return Ok(response.Value);
}
}
Injeção de dependências
Para que tudo isso funcione, você deve fazer a injeção de dependências correta do MediatR em sua aplicação. Neste ponto, faremos uso do pacote Nuget MediatR.Extensions.Microsoft.DependencyInjection.
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
Com o pacote devidamente instalado em seu projeto, basta fazer a injeção de dependências. Neste exemplo eu uso o injetor de dependências nativo do ASP.Net Core.
public void ConfigureServices(IServiceCollection services)
{
services.AddMediatR();
}
public void ConfigureServices(IServiceCollection services)
{
var assembly = AppDomain.CurrentDomain.Load("DemoMediatrAspNetCore.Application");
services.AddMediatR(assembly);
}
No primeiro exemplo, apenas executamos o método de extensão AddMediatR, que foi disponibilizado com a instalação do pacote acima. Esse método injetará todas as dependências necessárias para que o MediatR funcione corretamente, inclusive os Handlers.
O segundo exemplo faz a mesma coisa que o primeiro, com a diferença que podemos informar em qual assembly estão os Handlers.
Em um próximo artigo mostrarei como usar o recurso de Pipeline Behavior do MediatR.
Caso tenham quaisquer dúvidas, sugestões ou críticas, não deixem de entrar em contato. Ficarei feliz em responder.
Abraços!
Referências
- Repositório oficial do MediatR no GitHub
- Pacote Nuget do MediatR
- Pacote Nuget MediatR.Extensions.Microsoft.DependencyInjection
- Mediator Design Pattern
- GoF Design Patterns
- Livro Design Patterns: Elements of Reusable Object-Oriented Software
Artigo do autor pode ser visto também em:
https://static.imasters.com.br/wp-content/uploads/2019/01/21120411/MediatR-com-ASP.Net-Core.jpg/