Logo

dev-resources.site

for different kinds of informations.

Azure SignalR no .NET 8

Published at
12/13/2023
Categories
dotnet
dotnetcore
signalr
socket
Author
hgmauri
Categories
4 categories in total
dotnet
open
dotnetcore
open
signalr
open
socket
open
Author
7 person written this
hgmauri
open
Azure SignalR no .NET 8

SignalR

O SignalR é uma biblioteca open source da Microsoft criada em 2011 por Damian Edwards e David Fowler, com a finalidade de facilitar a implementação de aplicações que demandam funcionalidades em tempo real.  Essa funcionalidade permite que o código do lado do servidor envie conteúdo aos clientes instantaneamente.

Um exemplo clássico de utilização do SignalR é o chat, onde um cliente envia mensagem para outro cliente em tempo real, passando pelo servidor SignalR, que faz o papel de hub entre as duas conexões, trabalhando como uma classe que fornece endpoints que tornam o envio e o recebimento de mensagens em tempo real possível.

Neste artigo utilizaremos o Azure SignalR como serviço em um projeto .NET 8.

Configurando o SignalR no Azure

Os maiores benefícios em utilizar o SignalR no Azure são: escalabilidade, balanceamento de carga e baixa latência, deixando seu ambiente muito mais transparente, robusto e confiável.

Nosso primeiro passo é preparar e configurar o SignalR no Azure, clicando no serviço informado conforme imagem abaixo:

image

Em seguida, é necessário configurar os dados básicos da instalação. Neste exemplo utilizaremos a região sul do Brasil para instalar nosso servidor de socket:

image

Utilizaremos o tipo de serviço Default com o plano Standard do SignalR, esse plano é ideal para produção, pelo principal fato de contar com SLA de 99.9%. Em média, o valor mensal para esse serviço gira em torno de R$ 250,00, o que é muito barato, por exemplo, para uma infraestrutura com várias aplicações.

image

Logo depois da instalação, é necessário copiar a connection string, que será utilizada na nossa codificação .NET:

image

Configurando o SignalR no .NET 8

Para entender melhor como o SignalR funciona, utilizaremos três projetos:

  • SignalR.Socket.Server: Projeto principal utilizado como servidor socket, nele fica configurado o Azure SignalR e nossos hubs.
  • **SignalR.Socket.Receive: Projeto responsável por receber notificações que passam pelo SignalR.
  • SignalR.Socket.Sender: Projeto de exemplo de envio de mensagens de uma ponta à outra.

image

No projeto Server é necessário instalar o pacote Microsoft.Azure.SignalR e configurar nosso startup.cs com a connection string do Azure SignalR

public class Startup
{
    const string CORS_SIGNALR_POLICY_NAME = "signalr";
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSignalR(options =>
        {
            options.KeepAliveInterval = TimeSpan.FromMinutes(20);
            options.ClientTimeoutInterval = TimeSpan.FromMinutes(40);
            options.HandshakeTimeout = TimeSpan.FromMinutes(5);
            options.MaximumParallelInvocationsPerClient = 10;
            options.MaximumReceiveMessageSize = 10 * 1024 * 1024;
            options.StreamBufferCapacity = 50;
            options.EnableDetailedErrors = true;
        }).AddAzureSignalR(Configuration.GetSection("AzureSignalR:ConnectionString").Value);

        services.AddCors(options =>
        {
            options.AddPolicy(CORS_SIGNALR_POLICY_NAME, builder => builder
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .SetIsOriginAllowed((host) => true)
                    .AllowCredentials()
            );

        });

        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseCors(CORS_SIGNALR_POLICY_NAME);
        app.UseRouting();

        app.UseAuthorization();

        app.UseAzureSignalR(routes =>
        {
            routes.MapHub<SocketHub>("/sockethub");
        });

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGet("/", async context =>
            {
                await context.Response.WriteAsync("Socket no ar!");
            });
            endpoints.MapControllers();
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

Repare que a configuração do CORS está permitindo todos os tipos de conexões, o que não é indicado por questão de segurança, deixado apenas para realizar nossos testes.

Existem configurações extras em AddSignalR, que foram de acordo com a documentação oficial, onde também indicam as boas práticas de utilização.

Nosso próximo passo é configurar o hub, chamado de SocketHub.cs:

public class SocketHub : Hub
{
    public override async Task OnConnectedAsync()
    {
        var context = Context.GetHttpContext();

        lock (UserSocket.UsersSocket)
        {
            UserSocket.UsersSocket.Add(new Users
            {
                DateTime = DateTime.Now,
                Application = context?.Request?.Headers["Host"],
                Environment = context?.Request?.Headers["Origin"],
                ConnectionId = Context.ConnectionId,
                UserName = Context.User?.Identity?.Name ?? Context.ConnectionId
            });
        }

        await base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception exception)
    {
        var user = UserSocket.UsersSocket?.FirstOrDefault(p => p.ConnectionId == Context?.ConnectionId);

        if (user != null)
        {
            lock (UserSocket.UsersSocket)
            {
                UserSocket.UsersSocket.Remove(user);
            }
        }

        await base.OnDisconnectedAsync(exception);
    }

    public async Task SendPrivateMessage(string login, string type, string message, string body)
    {
        var connectionId = UserSocket.UsersSocket.Where(x => x.UserName == login);

        foreach (var connection in connectionId)
        {
            await Clients.Client(connection.ConnectionId).SendAsync("ReceiveMessage", login, type, message, body);
        }
    }

    public async Task SendNotification(string mensagem)
    {
        await Clients.All.SendAsync("ReceiveGenericEvent", mensagem, DateTime.Now.Ticks.ToString());
    }
}
Enter fullscreen mode Exit fullscreen mode

Além dos métodos de sobrecarga de conectar e desconectar, temos o método SendPrivateMessage responsável por enviar uma mensagem para um usuário específico e o método SendNotification, que é responsável por enviar uma mensagem para todos clientes que estiverem "escutando" o método ReceiveGenericEvent.

amos configurar o pacote Microsoft.AspNetCore.SignalR.Client no projeto Sender (Console Application), responsável por enviar mensagens:

static async Task SenderClient(string nomeUsuario)
{
    var connection = new HubConnectionBuilder()
        .WithUrl("http://localhost:5005/sockethub", options =>
        {
            options.Headers["Application"] = "API Sender";
        })
        .WithAutomaticReconnect()
        .Build();

    await connection.StartAsync();
    Console.WriteLine("Connection started.");

    connection.Closed += async (error) =>
    {
        await Task.Delay(new Random().Next(0, 5) * 1000);
        await connection.StartAsync();
    };

    while (true)
    {
        Thread.Sleep(400);

        await connection.SendAsync($"SendNotification", $"{nomeUsuario} - {DateTime.Now:G}");
        Console.WriteLine($"Send Message: {nomeUsuario} - {DateTime.Now:G}");
    }
}
Enter fullscreen mode Exit fullscreen mode

A classe HubConnectionBuilder é responsável pela conexão com nosso servidor SignalR (que está em execução na url http://localhost:5005/sockethub), nela também temos o método WithAutomaticReconnect() que é utilizado como resiliência para manter a conexão sempre ativa com nosso servidor.

Finalmente temos a configuração do projeto Receive (Console Application), responsável por receber todas as mensagens enviadas pelo projeto Sender:

static async Task Main(string[] args)
{
    var connection = new HubConnectionBuilder()
        .WithUrl("http://localhost:5005/sockethub", options =>
        {
            options.Headers["Application"] = "API Receive";
        })
        .WithAutomaticReconnect()
        .Build();

    await connection.StartAsync();
    Console.WriteLine("Connection started.");

    connection.On<string, string>("ReceiveGenericEvent", async (id, runningTime) =>
    {
        await ReceiveAsync(id, runningTime);
    });

    connection.Closed += async (error) =>
    {
        await Task.Delay(new Random().Next(0, 5) * 1000);
        await connection.StartAsync();
    };
    Console.ReadLine();
}

private static Task ReceiveAsync(string id, string runningTime)
{
    Console.WriteLine($"Receive Message: {id} - {runningTime}");
    return Task.CompletedTask;
}
Enter fullscreen mode Exit fullscreen mode

O subscribe do método ReceiveGenericEvent do código acima é configurado no método SendNotification do nosso SocketHub.cs.

Para testar, é necessário marcar todos os três projetos como inicializáveis no Visual Studio:

image

Ao executar os três projetos, é possível ver a orquestração de mensagens do SignalR:

image

É muito simples, seguro e prático de configurar e utilizar o Azure SignalR, uma ferramenta incrível que pode ser utilizado em vários cenários, principalmente em ambientes com microservices, comunicações entre o backend / frontend e chamadas assíncronas.

Os detalhes completos você encontra no meu GitHub: https://github.com/hgmauri/signalr-socket-dotnet5

socket Article's
30 articles in total
Favicon
Getting Started with Web Sockets in Node.js
Favicon
Realtime Location Tracker & Communications
Favicon
Building an Event-Driven Socket Server in Python
Favicon
Creating an IoT Device Frontend: A High-Level Overview
Favicon
🔥 Building a Real-Time Chat App with Sockets in Next.js 💬
Favicon
Real-time notifications with React and Socket-IO
Favicon
How to Use Socket.IO to Build Your First Multiplayer Tic-Tac-Toe Game
Favicon
Enhance your Retool application with real-time chat functionality using a custom component!
Favicon
Building a Skribbl.io Clone: From Concept to Completion
Favicon
Real-Time Features in MERN Applications
Favicon
Building a Real-Time Video Chat App with WebRTC, Socket.io, Node.js, and React .
Favicon
Chat Server in Ruby Sockets
Favicon
[Book Review] Beej's Guide to Network Programming
Favicon
Networking and Sockets: Syn and Accept queue
Favicon
Networking and Sockets: Endianness
Favicon
Getting Started with Networking and Sockets
Favicon
Let's Dive into the World of Web Sockets: A Beginner's Guide
Favicon
Building Real-Time Views Component: A Socket.IO and Next.js Tutorial
Favicon
Full Stack Chat App with Socket.io
Favicon
Multiplayer Checkers game made with PhaserJS, ReactJS, NestJS, SocketIO
Favicon
Exploring ChronoSocketHub: A Comprehensive Real-time Communication and Job Scheduling Solution for Node.js
Favicon
Azure SignalR no .NET 8
Favicon
Connection io socket is not showing in console
Favicon
Use socket.io in react native with nodejs server
Favicon
A Full Stack Chatting App using Socket.io
Favicon
How can I use remote control with Fire TV without ADB in IOS
Favicon
Sockets for real-time data flow with Django Rest Framework
Favicon
Visualized radio-streaming w/ React/Vite/Node/Socket.io
Favicon
Golang CLI-based Socket MultiChat Tutorial
Favicon
Building Interactive Real-Time Apps with Socket.IO in Node.js:

Featured ones: