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
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Disabilitare automaticamente un workflow di GitHub
Utilizzare la versione generica di EntityTypeConfiguration in Entity Framework Core
Ottimizzare la latenza in Blazor 8 tramite InteractiveAuto render mode
Effettuare il refresh dei dati di una QuickGrid di Blazor
Supportare il sorting di dati tabellari in Blazor con QuickGrid
Ordinare randomicamente una lista in C#
Eseguire query verso tipi non mappati in Entity Framework Core
Sfruttare i KeyedService in un'applicazione Blazor in .NET 8
Recuperare l'ultima versione di una release di GitHub
Definire stili a livello di libreria in Angular
Eseguire un metodo asincrono dopo il set di una proprietà in Blazor 8
Creare una libreria CSS universale: i bottoni