Connettersi ad ASP.NET Core SignalR da Blazor WebAssembly

di Marco De Sanctis, in ASP.NET Core,

ASP.NET Core SignalR è probabilmente una della librerie più popolari nell'ecosistema di ASP.NET Core, visto che consente con grande semplicità di rendere interattive le nostre applicazioni, permettendo al server di inviare messaggi ai client connessi grazie al protocollo WebSockets.

Blazor WebAssembly si integra pienamente con SignalR, così che possiamo connetterci al server e implementare le nostre logiche interamente in C#. Vediamo come.

Creazione dell'Hub lato server


Immaginiamo di avere un'applicazione ASP.NET Core che esponga un semplice Hub, come quello in basso, che permette di ricevere un messaggio e girarlo a tutti i client collegati:

internal class MyHub : Hub
{
    public async Task SendMessageAsync(string message)
    {
        await this.Clients.All.SendAsync("messageReceived", message);
    }
}

Un Hub del genere può essere associato a un URL nel metodo Configure della classe Startup:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // altro codice qui...

    app.UseEndpoints(endpoints =>
    {
        ...
        endpoints.MapHub<MyHub>("/hubs/myhub");
    });
}

Connessione lato client da Blazor WebAssembly


Per sfruttarlo il nuovo Hub da Blazor, come prima cosa dobbiamo aggiungere il package NuGet Microsoft.AspNetCore.SignalR.Client:

dotnet add package Microsoft.AspNetCore.SignalR.Client

A questo punto, possiamo creare una connessione direttamente da un nostro componente, come nell'esempio in basso:

@page "/"
@inject NavigationManager Navigation
@implements IAsyncDisposable
@using Microsoft.AspNetCore.SignalR.Client

@* .... altro codice qui .... *@

@code{ 
    private HubConnection _hubConnection;

    private List<string> _receivedMessages = new List<string>();

    protected override async Task OnInitializedAsync()
    {
        base.OnInitialized();
        _hubConnection = new HubConnectionBuilder()
            .WithUrl($"{this.Navigation.BaseUri}hubs/myhub")
            .Build();

        _hubConnection.On<string>("messageReceived", message =>
        {
            _receivedMessages.Add(message);

            this.StateHasChanged();
        });

        await _hubConnection.StartAsync();
    }

    public ValueTask DisposeAsync()
    {
        return _hubConnection.DisposeAsync();
    }
}

All'interno del metodo OnInitializedAsync, creiamo una HubConnection che punti all'URL dell'Hub sul server.

Nel nostro caso, stiamo utilizzando un'applicazione Blazor in hosting sullo stesso sito ASP.NET Core che espone l'Hub, per cui abbiamo recuperato l'indirizzo assoluto tramite il BaseUri di NavigationManager. Ovviamente i concetti rimangono assolutamente gli stessi anche nel caso in cui l'Hub risieda su una API esterna, a patto di avere la corretta configurazione di CORS.

Successivamente agganciamo un handler all'evento messageReceived, per aggiungere il nuovo messaggio ricevuto a una collection di _messages e invalidare lo stato del componente, forzandone un nuovo rendering, con una chiamata a StateHasChanged.

Come ultimo passo abbiamo poi, avviamo la connessione chiamando il metodo StartAsync. Un aspetto di cui dobbiamo tener conto è che essa rimarrà attiva per tutta la durata del ciclo di vita di HubConnection. Implementando l'interfaccia IDisposableAsync sul componente, però, possiamo effettuare il DisposeAsync, così da evitare connection leak.

Inviamo e visualizziamo i messaggi


Ora possiamo finalmente implementare la logica per visualizzare e inviare messaggi. Il markup può essere una semplice lista seguita da una InputBox e un Button:

<div>
    <ul>        @foreach (var message in _receivedMessages)
        {
            <li>
                @message
            </li>
        }
    </ul>
</div>
<div>
    <input type="text" @bind="_newMessage" />
    <button class="btn btn-primary" @onclick="SendMessageAsync">Send</button>
</div>

Il metodo SendMessageAsync invocato al click del button, si occupa di inviare il messaggio all'Hub tramite il codice seguente:

private string _newMessage;

private async Task SendMessageAsync()
{
    if (!string.IsNullOrWhiteSpace(_newMessage))
    {
        await _hubConnection.SendAsync("SendMessageAsync", _newMessage);
        _newMessage = string.Empty;
    }
}

Per verificare se abbiamo svolto tutti i passaggi correttamente, ci basterà avviare l'applicazione in un paio di tab differenti: un messaggio inviato da uno dei due apparirà immediatamente su tutti i client connessi:

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi