Messaggi in tempo reale con Blazor Server

di Moreno Gentili, in ASP.NET Core,

In un precedente script abbiamo visto come, usando Blazor Server, si possa aggiornare la UI a seguito di un evento di navigazione (https://www.aspitalia.com/script/1354/Paginare-Elenco-Blazor-Server.aspx). Questa tecnica può essere estesa a tutti i tipi di evento sollevati dai componenti della nostra applicazione, così che possiamo notificarli al client in tempo reale. Vediamo l'esempio di un servizio che solleva eventi ad intervalli regolari.

Creare un servizio di notifica messaggi

Iniziamo defininendo un'interfaccia IMessageNotifier che espone un evento MessageArrived.

public interface IMessageNotifier
{
  event EventHandler<string> MessageArrived;
}

Creiamo una classe Worker che implementa l'interfaccia e solleva l'evento una volta al secondo. Questa classe è un Hosted Service, ovvero un servizio idoneo a eseguire delle operazioni in background, così come mostrato in un precedente script (https://www.aspitalia.com/script/1276/Operazioni-Background-Hosted-Service-ASP.NET-Core.aspx).

public class Worker : BackgroundService, IMessageNotifier
{
  public event EventHandler<string> MessageArrived;
  
  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      //Questo worker genera un messaggio che riporta la data e l'ora corrente
      string message = $"Message sent at {DateTime.Now}";

      //Solleviamo l'evento per notificare il messaggio ai sottoscrittori
      MessageArrived?.Invoke(this, message);

      //E infine attende un secondo prima di generare il successivo messaggio
      await Task.Delay(1000, stoppingToken);
    }
  }
}

Adesso registriamo la classe Worker per la dependency injection: facciamo in modo che venga registrata sia come Hosted Service che come implementazione concreta del servizio IMessageNotifier. Inseriamo quanto segue nel metodo ConfigureServices della classe Startup.

services.AddSingleton<Worker>();
services.AddSingleton<IMessageNotifier>(serviceProvider => serviceProvider.GetService<Worker>());
services.AddHostedService(serviceProvider => serviceProvider.GetService<Worker>());

Ora è tutto pronto e possiamo passare alla realizzazione del Razor Component che sottoscrive l'evento.

Visualizzare gli eventi in un Razor Component

In un'applicazione Blazor Server, il client è sempre connesso all'applicazione grazie a una connessione persistente e bidirezionale basata su WebSockets, che può essere sfruttata dal server per inviare messaggi. Vediamo quindi l'esempio di un Razor Component che visualizza tali messaggi in tempo reale.

@page "/messages"
@inject IMessageNotifier notifier
@implements IDisposable

<h1>Messages</h1>
<ul>  @foreach (var message in messages)
  {
  <li>@message</li>
  }
</ul>

@code {
  //Questa lista contiene l'elenco dei messaggi ricevuti
  private List<string> messages = new List<string>();
  protected override void OnInitialized()
  {
    //Ad inizializzazione avvenuta, sottoscriviamo la ricezione di eventi
    notifier.MessageArrived += DisplayMessage;
  }

  private void DisplayMessage(object sender, string message)
  {
    //Usiamo InvokeAsync per far eseguire questo codice
  //al thread del renderer, altrimenti avremmo un'eccezione
    InvokeAsync(() => 
    {
      //Aggiungiamo il messaggio in cima alla lista
      messages.Insert(0, message);

      //E rimuoviamo quelli in eccesso, così da non visualizzarne troppi
      while (messages.Count > 50)
      {
        messages.RemoveAt(50);
      }
      //Segnaliamo che lo stato è cambiato
      StateHasChanged();
    });
  }

  public void Dispose()
  {
    //Rimuoviamo la sottoscrizione quando
  //il Razor Component non serve più
    notifier.MessageArrived -= DisplayMessage;
  }
}

Come si vede nell'esempio, riceviamo un riferimento al servizio IMessageNotifier per mezzo della direttiva @inject. Inoltre, è importante aggiungere la direttiva @implements IDisposable e definire il metodo Dispose per rimuovere la sottoscrizione all'evento MessageArrived. In questo modo il Razor Component potrà essere deallocato correttamente dal Gargabe Collector quando non serve più.

Visualizzare i messaggi su richiesta dell'utente

Se vogliamo consentire all'utente di interrompere e riprendere la visualizzazione dei messaggi, possiamo aggiungere una checkbox come la seguente.

<input type="checkbox" id="follow" @bind="followMessages">
<label for="follow">Follow messages</label>

Lo stato di selezione della checkbox verrà messo in binding su un campo privato followMessages di tipo booleano che definiamo nel Razor Component. Nel caso in cui il suo valore sia false, evitiamo che il messaggio venga visualizzato nella UI. Perciò modifichiamo il codice come segue.

//Definiamo il campo privato
private bool followMessages = true;
private void NotifyMessage(object sender, string message)
{
  //Usciamo precocemente se il suo valore è false
  if (!followMessages)
  {
    return;
  }
  
  //Qui si trova il codice già visto nel precedente esempio
}

Avviamo l'applicazione e verifichiamo che la checkbox ci permette, appunto, di interrompere e riprendere il flusso di messaggi che vengono visualizzati ogni secondo.

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