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.

1
2
3
4
5
6
7
8
9
10
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:

1
2
3
4
5
6
7
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.

1
2
3
4
5
using Microsoft.AspNetCore.SignalR;
public class Notificacao:Hub
{
 
}

Enviando uma notificação

1
2
3
4
5
6
7
8
9
10
11
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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:

1
2
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