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