Envie notificações com classe: (.NET 5 + Apache Kafka + MediatR + SignalR)

Renan Alves Medina
sysmap-labs
Published in
7 min readOct 21, 2021

Opa beleza? Hoje vou trazer exemplo de um serviço de envio de push notifications em realtime com .NET de ponta a ponta. Teremos várias tecnologias como .NET 5, Apache Kafka, MediatR, SignalR…

Segura que a story vai longe e no final você terá um Push Notification service pronto para colocar em produção!

Para os Talk is cheap, Show me the code:

Antes de seguirmos com o passo a passo deixarei para você alguns conceitos que utilizaremos neste projeto.

Apache Kafka

É uma plataforma de streaming de eventos/mensageria comumente utilizada em ambientes de alto desempenho com software distribuído.
O Kafka combina 3 recursos chave no uso para streaming de eventos:
- Publicar e assinar fluxos de eventos;
- Armazenar mensagens de forma duradoura e confiável;
- Processar alto fluxo de eventos de forma ativa ou reativa;

MediatR

É um padrão de projeto usado frequentemente quando deseja-se encapsular como os objetos interagem, ou seja, a comunicação entre os objetos é estabelecida através do MediatR. Com MediatR reduzimos o acoplamento evitando que projetos/camadas/objetos se referiram uns aos outros explicitamente.

SignalR

Uma biblioteca para recursos realtime em serviços web/mobile. Com SignalR você pode criar features que recebem dados de forma reativa em tempo real. Esta lib tem a capacidade de lidar com gerenciamento de conexões de clientes automaticamente, enviar mensagens de diversos tipos a todos estes clientes ou mesmo ao um grupo específico.

Conceitos explicados agora vamos ao nosso objetivo aqui…

Iremos construir um serviço .NET que terá duas partes, na primeira teremos um WorkerService em background, este ficará “ouvindo” uma fila do Kafka e dado uma nova mensagem produzirá uma notificação. Para segunda parte do serviço terá um Handler do MediatR esperando por essa notificação. O handler fará uso da lib do SignalR para enviar para todos os clients conectados no Hub essa notificação.

E lá vamos nós…

# Provisionando o Kafka

  • Para subir a infra do Apache Kafka usaremos o Docker Compose por ser uma forma bem efetiva e rápida. Deixarei abaixo o docker-compose.yml que utilizei.
  • Abra no terminal o diretório que você criou o arquivo docker-compose.yml e execute o comando “docker-compose up”.
  • Após a conclusão do provisionamento da infra do Kafka, execute o comando abaixo em uma nova aba do terminal para criar o tópico que usaremos neste projeto.
docker exec -it zookeeper kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 3 --topic event-push-notification

# Criando o serviço .NET

Iremos criar um projeto “ASP.NET Core Empty”, o nomeei como “PushNotifications.Service” e a Solution como “PushNotifications” e como já dito usaremos o .NET 5.

Criando o projeto .NET

# Criando o WorkerService

Projeto criado, já na raiz iremos adicionar uma classe chamada de “Woker”, será um BackgroundService que funcionará como consumer das mensagens na fila do Kafka.

Adicionaremos neste Worker uma herança da classe BackgroundService, injetaremos também duas dependências, uma para o conhecido ILogger e para uma implementação que faremos em seguida, IEventService.
Com as dependências injetadas, criamos também um construtor e o override do método ExecuteAsync.
Abaixo como ficará o código do Worker.

# Criando o EventService

Na raiz do projeto criaremos uma pasta chamarei de “Services” nesta pasta adicionaremos uma classe chamada “EventService” e uma interface seguindo o padrão “IEventService”.

Instalaremos 3 pacotes, Confluent.Kafka, MediatR e Newtonsoft.Json. Para isso usaremos as seguintes linhas de comando:
Install-Package Confluent.Kafka -Version 1.8.2
Install-Package MediatR -Version 9.0.0
Install-Package Newtonsoft.Json -Version 13.0.1

Agora sim, vamos pro código…

Teremos 2 métodos, chamaremos o primeiro de “Subscribe” que como o nome já indica será responsável por realizar o subscribe no topic do Kafka e ficar “ouvindo” a fila aguardando por um novo evento.

O segundo método será o “NextEvent” e este será acionado quando uma nova mensagem for postada na fila.
No NextEvent iremos consumir a mensagem e deserializar usando a model do nosso evento que já criaremos em seguida. Após está criação realizaremos o envio do evento para o MediatR usando o método “Publish”.

Criado a classe, temos que adicionar na interface “IEventService” o método Subscribe. Agora voltamos na classe “Worker” e adicionar a referência para o IEventService que ficou faltando.

O código da nossa classe EventService ficará desta forma:

# Criando o PushNotificationEvent

Na raiz do projeto criaremos uma pasta, chamarei de “Events” nesta pasta adicionaremos uma classe chamada “PushNotificationEvent” que será a model e herdará o tipo INotification do MediatR.

Criado a model, basta voltar na classe “EventService” e adicionar a referência para o PushNotificationEvent que ficou faltando.

Concluímos a primeira parte deste projeto audacioso que se tratava em consumir eventos de uma fila do Kafka e publicá-los como INotifications para o MediatR.

Vamos começar agora a segunda parte aqui criaremos um Handler, um SignalR Hub e faremos os acertos finais para tudo ficar 100%.

# Criando o PushNotificationHandler

Adicionaremos na pasta “Events” uma classe chamada de “PushNotificationHandler”. Está classe irá herdar a interface “INotificationHandler<TNotification>”.

Agora vamos adicionar o pacote do SignalR que usaremos nesta parte. Para isso usaremos a seguinte linha de comando:
Install-Package Microsoft.AspNetCore.SignalR -Version 1.1.0

Teremos na classe o método “Handle”, aqui ficará a lógica para serializar nossa model e enviar a notificação utilizar o “IHubContext<THub>”.

# Criando o PushNotificationHub

Aqui chegamos ao passo de adicionar o ponto de entrada para as conexões Websocket do SignalR. Os hubs chamam o código do lado do cliente enviando mensagens que contêm o nome e os dados.

Adicionaremos na raiz do projeto uma pasta chamada “Hubs” e nela ficará a classe “PushNotificationHub” que será bem simples apenas herdando a classe “Hub” da lib do SignalR.

Retornamos agora no PushNotificationHandler e adicionamos a referência que faltava para o PushNotificationHub.

# Configurando os Extensions e toques finais

Começaremos este passo criando na raiz do projeto uma classe que chamei de “ServiceExtensions” está classe criei com intuito de organizar as coisas, aqui iremos ter um método chamado de AddEventService que irá registrar a DI do EventService e do kafka. Registrei também as configurações de consumer do kafka que não detalharei neste story pois renderia uma longa conversa.

Antes de realizar as configs do startup, teremos que adicionar um pacote, este irá nos auxiliar a registrar as dependências do MediatR. Para isso usaremos a linha de comando abaixo:
Install-Package MediatR.Extensions.Microsoft.DependencyInjection -Version 9.0.0

Com o pacote instalado podemos seguir com os ajustes na classe startup!

Nela iremos começar adicionando um HostedService, lembram daquele Worker que fizemos láaa… atrás :) pois é, chegou a hora de dizer que este cara será iniciado no nosso projeto.

Também teremos uma parte que é mais uma dica que irá facilitar sua vida, registre uma policy para Cors e evite problemas na hora de conectar seus clients.

Agora vamos registrar as 3 DIs que faltam, AddSignalR, AddMediatR e finalmente nosso AddEventService.
Feito isso precisamos adicionar no método Configure referência para nossa CorsPolicy e o Map do endpoint para PushNotificationHub.

# Vamos testar né ???

Uffa galera, conseguimos finalizar nosso projeto! Agora vou ajudar vocês a testar este cara de forma mais rápida.

Vou deixar aqui o link para dois repos:

No primeiro link vocês poderão baixar um projeto .NET para produzir mensagens no Kafka. Com esse projeto você pode postar mensagens no seu kafka que serão consumidas pelo serviço que acabamos de criar.
No segundo link deixei um client reactJs, com ele vocês poderão ver as notificações chegando para um front web.

  • Primeiro executaremos o projeto PushNotification.Service;
  • Executaremos agora o push-notification-client;
  • Em seguida dotnet run no projeto KafkaProducer, ele irá produzir mesangens em nosso tópico Kafka.
  • Veremos então as mensagens sendo consumidas no PushNotification.Service.
  • Agora temos notificações chegando em nosso client React e sendo mostrados no Front.

# Conclusão

Chegamos ao fim, com alegria concluímos este projeto que foi muito legal de fazer e espero que ajude vocês e aguce as ideias que surgirão para aplicarem tudo que usamos aqui.

Sucesso galera e que possamos ser InovationKeepers sempre!

Ass. Renan Alves Medina

--

--