ASP NET Core, SignalR e Angular 8: Criando um painel de cotações de ações com dados em tempo real

Já se perguntou como desenvolver aplicações com atualizações em tempo real, como chats, dashboards de corretoras e notificações de redes sociais? Eu também! 

A ferramenta que eu e você buscávamos, trazendo para o universo .NET, é o SignalR. Vou falar dele e de alguns conceitos relacionados, além de mostrar a implementação de um exemplo daora que utiliza o ASP.NET Core e o Angular 8 para mostrar atualização de cotação de ações em tempo real. 

As ações de empresas têm seu preço atualizado de maneira contínua durante o tempo de abertura do mercado, como consequência de operações de participantes dele. Para dar suporte a um cenário como esse, assim como cenários de mensagería instantânea, é necessário enviar dados para o cliente da aplicação de maneira contínua, em tempo real.

Assim, o cliente pode acompanhar a variação dos preços das ações nas quais ele tem interesse, sem precisar atualizar a página para obter os dados mais recentes.

O resultado final da aplicação desenvolvida é o seguinte, onde os valores de cada ação são atualizados a cada 5 segundos, junto com a variação de preço (em %):

Atualização em tempo-real de dados de cotação no front-end

Estou atualizando os valores de maneira aleatória no back-end, dentro de um intervalo.

Repositório com o código-fonte completo (front-end e back-end) luisdeol/realtime-broker: Exemplo de utilização do SignalR para atualização de dados em tempo-real, aplicado a um dashboard fictício de ações. …github.com


SignalR

O que é

O SignalR é uma biblioteca (open-source) que permite adicionar funcionalidades em tempo real para sua aplicação, de maneira simplificada. Quando disponível, o SignalR utiliza o técnica de transporte WebSocket, que é mais eficiente quanto à memória do servidor, tem menor latência e também permite a conexão bi-direcional entre cliente e servidor. Assim, o cliente consegue enviar dados ao servidor, e o servidor consegue “empurrar” dados para o cliente.

Adicionamos o SignalR ao projeto através da classe Startup, adicionando ao método ConfigureServices a chamada ao método AddSignalR pelo objeto de tipo IServiceCollection.

Código:

Registrando o serviço do SignalR na classe Startup

Hub

Os Hubs do SignalR permitem a chamada de métodos dos clientes pelo servidor, e vice-versa. Através dele o servidor consegue notificar o cliente de novas atualizações em tempo-real, e o cliente consegue estabelecer novas conexões e aguardar por novos dados, por exemplo.

A implementação é simples, visto que a única atividade realizada é a de “inscrição” em uma ação. Logo, precisamos apenas de um método, que receberia o código da ação (ITSA4, por exemplo), e adicionaria o cliente àquele grupo. Assim, toda vez que uma ação fosse notificada de alteração no preço, todos os clientes inscritos nela receberiam o valor atualizado.

Criando um Hub do SignalR

Com o método definido acima, os clientes conseguem se inscrever nas ações e aguardar por dados de atualização de seus dados.

Para disponibilizar um Hub para o “mundo exterior”, precisamos mapeá-lo a uma rota. Conseguimos isso também na classe Startup, porém dessa vez adicionamos ao método Configure a chamada de UseSignalR pelo objeto de tipo IApplicationBuilder.

Código:

Adcionando os Hubs nas rotas da aplicação

Grupos

Um grupo permite o agrupamento de diversas conexões em torno de um nome. No nosso exemplo, o nome é o código de uma ação. Porém, poderia ser um identificador de um usuário (em caso de uma notificação, por exemplo) ou grupo (em caso de um app de mensagería, por exemplo). Através dos grupos os Hubs conseguem se comunicar com coleções específicas de conexões e atualizá-las de maneira exclusiva.

Como atualizar os dados?

Para a atualização dos dados, decidi utilizar um HostedService. Caso não conheça esse recurso do ASP.NET Core, deixo aqui a leitura deste outro artigo meu. De maneira resumida, ele permite a execução de código em uma rotina.

Definimos então uma rotina de 5000ms, que correspondente a 5 segundos (para o GIF usei 1000ms, ou 1 segundo). É um intervalo suficiente para notarmos as alterações na tela sem quaisquer problemas.

Certo, mas como podemos atualizar os dados de um grupo de um Hub, quando estamos FORA do contexto dele? Isso requer a obtenção da instância de escopo IHubContext<T>, onde T é uma classe que herda de Hub.

Através dessa instância, conseguimos acessar a propriedade Clients, que então permite executar uma operação em clientes conectados ao Hub. Com o método Group, podemos passar o código da ação correspondente, e então notificar o novo valor, passando também o nome do método. É essencial que o nome desse método seja o mesmo que o cliente front-end utilizará para receber os eventos.

Código:

Implementação de um Hosted Service

Angular 8

Biblioteca aspnet/signalr

A biblioteca que será utilizada para iniciar a conexão usando socket com o back-end será o pacote npm chamado aspnet/signalr.

Para instalá-lo em sua aplicação, utilizar o comando abaixo.

Instalando o pacote @aspnet/signalr via NPM

Quando o construtor do componente é iniciado, eu crio a conexão usando o HubConnectionBuilder passando a URL do Hub ao método withUrl, gerando um HubConnection com a chamada do método build. Após isso, me inscrevo nos eventos que tenho interesse usando o método on, e finalmente inicio a conexão com o método start. Além disso, inicio um dicionário contendo os códigos das ações (ITSA4, TAEE11 e PETR4), além de seu valor inicial. Esses valores seriam preenchidos como você desejar, através de uma chamada HTTP GET para uma API que contenha seus dado, por exemplo.

O código completo utilizado para isso está logo abaixo.

Implementação do código TypeScript do componente Angular

No código acima os itens do dicionário são percorridos, e em seguida a “inscrição” para cada ação é feita ao se invocar o método ConnectToStock do Hub do SignalR criado anteriormente. A partir desse momento, os grupos do SignalR para cada ação já tem clientes conectados, e poderão enviar os dados atualizados que serão recebidos pelo evento UpdatePrice (definido no método registerOnServerEvents.

O HTML desse componente não é nada de outro mundo. Log abaixo está o código usado para renderizar as ações e mudar a exibição de acordo com a variação do valor.

Implementação do código HTML do componente Angular

Executando o projeto

Baixe o projeto do repositório do início do artigo

Navegue para a pasta onde desejar que o projeto seja clonado. Execute o seguinte comando:

Comando para clonar o projeto utilizando o Git

Instalar os pacotes da aplicação Angular

Via linha de comando, vá para a pasta front-dashboard-stocks, do projeto clonado. Execute o seguinte comando:

Instalar os pacotes da aplicação utilizando NPM

Rodar a aplicação ASP.NET Core

Navegue para a pasta RealTimeBroker/RealTimeBroker.Web, do projeto clonado, e execute o seguinte comando:

Restaurando os pacotes, e executando a aplicação ASP.NET Core

Iniciar a aplicação Angular

Via linha de comando, vá para a pasta front-dashboard-stocks, do projeto clonado. Execute o seguinte comando:

Iniciando a aplicação Angular

Navegue para http://localhost:4200 para abrir a aplicação!

Tela da aplicação Angular que está executando

Desafio

Usando os conceitos de Hub e Groups, que tal tentar criar uma aplicação de chat em grupos, estilo Whatsapp? Você poderia definir um identificador para o grupo, abrir duas abas distintas e acessar a mesma página delas. O cliente front-end se inscreveria para o mesmo identificador, e quando uma mensagem fosse enviada pelo método do Hub, todos clientes desse grupo seriam notificados. Compartilha aí se aceitar!


Inscreva-se na lista de espera do Método .NET Direto ao Ponto, um treinamento completo sobre C#, APIs com ASP.NET Core e Microsserviços:  Inscreva-se aqui.

São quase 200 vídeo-aulas sobre temas como C#, ASP NET Core 5, EF Core, CQRS, Clean Architecture, Autenticação e autorização com JWT, Testes Unitários, além de mini-cursos em Microsserviços, Performance em .NET, ASP NET Core e Azure, Docker, Carreira Internacional em .NET, e mais.


Conclusão

Pelo que foi apresentado, concluímos que entender bem o que o SignalR faz abre portas para adicionarmos atualizações em tempo real em nossas aplicações, como notificações de eventos, atualização de cotações, etc.

Espero que tenha sido útil, até a próxima!