RealTime con SignalR

in ASPNET Core, C#

Dotnet Core e SignalR

Reading Time: 3 minutes

SignalR non è sicuramente una novità: è stato, infatti, introdotto all’interno di ASP.NET circa cinque anni fa come strumento per la creazione di applicazioni real-time. Nel 2018, con il rilascio di .NET Core 2.1, è stato rilasciato anche all’interno di .NET Core: è quindi disponibile per l’integrazione all’interno di applicazioni cross-platform. SignalR è perfettamente integrato all’interno della suite Azure il servizio SignalR che consente di creare servizi in tempo reale, come ad esempio bot, chat multipiattaforma e dashboard in tempo reale. Inoltre è consigliato in tutte quelle applicazioni che necessitano di update rapidi (con un alto rate di aggiornamento) oppure quando si ha la necessità di implementare la comunicazione full-duplex.

SignalR è una libreria open-source che consente di aggiungere notifiche real-time alle applicazioni web creando un canale bidirezionale tra client (browser) ed server (Web App).

E’ il framework ad ottimizzare il tipo di canale di comunicazione: gli sviluppatori possono dedicarsi allo sviluppo, senza addentrarsi all’interno degli aspetti tecnici della creazione/mantenimento del canale.

Rispetto alla versione precedente (ASP NET SignalR), la versione ASP NET Core presenta alcune differenze:

  • non supporta la riconnessione automatica del client nel caso in cui la connessione sia stata interrotta
  • supporta JSON e MessagePack (serializzazione binaria che crea dei messaggi più piccoli rispetto al JSON)
  • la libreria ASP.NET Core SignalR Client è stata totalmente riscritta in Typescript
  • non è più necessario includere la libreria JQuery in quanto sono state tolte tutte le dipendenze
  • la libreria client non è più disponibile all’interno di nuget, ma è possibile scaricarla direttamente da npm
  • supporto per Azure SignalR Service
  • supporto per SignalR scaleout with Redis

Utilizzo

Per poter utilizzare SignalR all’interno di un’applicazione ASP.NET Core è necessario aggiungere:

using Microsoft.AspNetCore.SignalR

In particolare, è contenuto all’interno del package :

Microsoft.AspNetCore.App 

Il funzionamento di SignalR è basata su due entità ben distinte:

  • Client: una libreria javascript che consente il collegamento dalle View (html) al server
  • Server: una o più classi che ereditano da Hub. All’interno di queste classi devono essere definiti i metodi pubblici, ad esempio per l’invio dei messaggi

Semplificando, le classi che eredidano da Hub espongono i metodi public, che possono essere richiamati dai client. Solo i metodo public possono essere richiamati.

Esempio – Realizzazione di una chat

Una volta creata l’appliazione è necessario modificare Startup.cs per abilitare l’utilizzo di SignalR, abilitando all’interno del metodo ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
   services.AddSignalR();
}

inoltre all’interno del metodo è necessario definire la route che verrà utilizzata dai client:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
 app.UseSignalR(routes =>
            {
                routes.MapHub<ChatHub>("/chat");
            });
}

Nell’esempio precedente la route definita è /chat .

Definiamo quindi la classe che eredita da Hub, all’interno della quale sono definiti i metodi pubblici raggiungibili dai client.

 public class ChatHub : Hub
    {
        public void Send(string name, string message)
        {           
            Clients.All.SendAsync("broadcastMessage", name, message);
        }
    }

All”interno della cartella /wwwroot possiamo creare una semplice pagina html (anche se la logica può essere ovviamente integrata all’interno di Views/Razor Pages). Per poter utilizzare signalr lato client è necessario includere la libreria (in questo caso in versione minimizzata):

<script type="text/javascript" src="lib/signalr.min.js"></script>

Di seguito il codice completo della pagina html :

<!DOCTYPE html>
<html>
<head>
    <title>SignalR Simple Chat</title>
    <style type="text/css">
        .container {
            background-color: #99CCFF;
            border: thick solid #808080;
            padding: 20px;
            margin: 20px;
        }
    </style>
</head>
<body>
    <div class="container">
        <input type="text" id="message" />
        <input type="button" id="sendmessage" value="Send" />
        <ul id="discussion"></ul>
    </div>
    <!--Script references. -->
    <!--Reference the SignalR library. -->
    <script type="text/javascript" src="lib/signalr.min.js"></script>
    <!--Add script to update the page and send messages.-->
    <script type="text/javascript">
        document.addEventListener('DOMContentLoaded', function () {
            var messageInput = document.getElementById('message');
            // Get the user name and store it to prepend to messages.
            var name = prompt('Enter your name:', '');
            // Set initial focus to message input box.
            messageInput.focus();
            // Start the connection.
            var connection = new signalR.HubConnectionBuilder()
                                .withUrl('/chat')
                                .build();
            // Create a function that the hub can call to broadcast messages.
            connection.on('broadcastMessage', function (name, message) {
                // Html encode display name and message.
                var encodedName = name;
                var encodedMsg = message;
                // Add the message to the page.
                var liElement = document.createElement('li');
                liElement.innerHTML = '<strong>' + encodedName + '</strong>:  ' + encodedMsg;
                document.getElementById('discussion').appendChild(liElement);
            });
            // Transport fallback functionality is now built into start.
            connection.start()
                .then(function () {
                    console.log('connection started');
                    document.getElementById('sendmessage').addEventListener('click', function (event) {
                        // Call the Send method on the hub.
                        connection.invoke('send', name, messageInput.value);
                        // Clear text box and reset focus for next comment.
                        messageInput.value = '';
                        messageInput.focus();
                        event.preventDefault();
                    });
            })
            .catch(error => {
                console.error(error.message);
            });
        });
    </script>
</body>
</html>

Da notare il codice javascript

connection.on('broadcastMessage'....)

che viene richiamato ogni volta che viene inviato un messaggio dall’HUB del server. Il resto viene gestito come codice javascript tradizionale.

SignalR è sicuramente un modo semplice e facilmente sviluppabile per poter realizzare applicazioni realtime. Oltre all’utilizzo all’interno di applicazioni di chat, è adatto per lo sviluppo di applicazioni che hanno la necessità di aggiornare dati con frequenza elevata, o realizzare applicazioni con comunicazione full-duplex.