Olá tudo bem?! Recentemente, em um dos projetos que estou atuando, surgiu a necessidade de notificar o usuário do sistema sobre a conclusão da execução de um processo, que é iniciada após uma determinada ação do usuário.
Neste meu cenário, eu não quero bloquear a transação e fazer meu usuário esperar até que o processo seja concluído. É importante o usuário saber a conclusão do processo, mas não quero impedi-lo de navegar no sistema. Para tal, decidimos utilizar o signalR como um webHook para notificar o usuário, independentemente de onde ele estiver no sistema.
Configurando o signalR
Basta adicionar o serviço do signalR no startup.cs da aplicação.
public class Startup { //... public void ConfigureServices(IServiceCollection services) { services.AddMvc(); //adicionar o serviço do signalR após o de MVC. services.AddSignalR(); } }
Agora defino a rota que o signalR utilizará para receber as notificações:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { //... app.UseSignalR(router => router.MapHub("/notificacao")); app.UseMvc(); }
Para esse cenário, a classe Notificacao.cs será somente uma implementação para o Hub.cs do signalR.
using Microsoft.AspNetCore.SignalR; public class Notificacao:Hub { }
Enviando uma notificação
public class ServicoDePublicacao{ private readonly IHubContext<Notificacao> _canalDeNotificacao; public ServicoDePublicacao(IHubContext<Notificacao> canalDeNotificacao) => _canalDeNotificacao = canalDeNotificacao; public async Task Publicar(){ await _canalDeNotificacao.Clients.All.SendAsync("NotificaPublicacao","Publicação com sucesso"); } }
Como podemos ver no código acima, para emitir uma notificação, basta eu obter uma referencia da minha conexão criada, utilizando a classe IHubContext, e enviar a mensagem desejada através dela.
No método Publicar estou basicamente enviando a mensagem para todos os clientes que estão assinando o “NotificaPublicacao”.
A primeira parte está feita. Agora vamos para o front-end e ver como obtemos essas notificações.
Configurando o angular
Primeiramente, baixe o pacote @aspnet/signalr na sua aplicação angular.
Criei um serviço na minha aplicação angular para me conectar com a rota do signalr definida no back-end. Segue código abaixo.
import { Injectable, EventEmitter, Output } from '@angular/core'; import { HubConnection, HubConnectionBuilder } from '@aspnet/signalr'; @Injectable() export class SignalRService { @Output() notificationReceived: EventEmitter; = new EventEmitter(); @Output() connectionEstablished: EventEmitter = new EventEmitter(); private _hubConnection: HubConnection; private baseUrl ="http://localhost:5001/notificacao"; constructor() { this.createConnection(); this.registerOnServerEvents(); this.startConnection(); } private createConnection() { this._hubConnection = new HubConnectionBuilder() .withUrl(this.baseUrl) .build(); } private registerOnServerEvents() { this._hubConnection .on('NotificaPublicacao', (data) => {console.log(data); this.notificationReceived.emit(data);}); } private startConnection(): void { this._hubConnection .start() .then(() => { console.log('Hub de conexão iniciado'); this.connectionEstablished.emit(true); }).catch(err => { console.log('Erro ao realizar conexão do signalR, tentando novamente'); setTimeout(this.startConnection(), 5000); }); } }
No serviço acima, estou basicamente criando uma conexão com o meu Hub de notificação, que foi criado no startup da minha Api, estou registrando as notificações que quero ouvir, que neste caso é a “NotificaPublicacao” e, por fim, me conecto ao Hub. Pronto. Agora em qualquer lugar que utilizar esse serviço, basta me inscrever no evento notificationReceived que, quando o signalr disparar alguma mensagem, meu front-end será notificado. Exemplo:
this.signalRService.notificationReceived.subscribe((notificacao) => console.log(notificacao))
Bem, é isso. Espero que tenham gostado e que seja util!
Obrigado!
(Cross-post de https://gustavofontes.net/2018/08/29/notificacao-de-processos-com-signalr-no-asp-net-core-angular/)
Gustavo Fontes