Nello script precedente (https://www.aspitalia.com/script/1327/Dati-Binari-Realtime-ASP.NET-Core-SignalR.aspx) abbiamo implementato la parte server di un'applicazione web che, grazie ad ASP.NET Core SignalR, invia immagini in tempo reale ai client connessi. Questo esempio è utile se dobbiamo monitorare le immagini catturate da una webcam oppure ricevere altro tipo di dati binari (o anche testuali) da dispositivi industriali o IoT.
Preparare il client
Ora continuiamo sviluppando la parte client, in cui andremo a ricevere i dati binari dal server e a visualizzarli in una pagina HTML. Per prima cosa aggiungiamo i riferimenti ai file JavaScript necessari.- Il client di ASP.NET Core SignalR (pacchetto npm @aspnet/signalr), che espone le funzionalità basilari per stabilire una connessione bidirezionale con il server;
- L'implementazione del protocollo MessagePack (pacchetto npm msgpack5) che contiene la logica di serializzazione dei messaggi in formato binario;
- Il supporto a MessagePack per SignalR (pacchetto npm @aspnet/signalr-protocol-msgpack).
Queste dipendenze client possiamo procurarcele in vari modi: usando libman (https://www.aspitalia.com/script/1304/Usare-LibMan-Gestire-Dipendenze-Client-ASP.NET-Core.aspx), npm, oppure semplicemente referenziando i file da un CDN come jsdelivr, proprio come mostrato in questo esempio. Possiamo aggiungere questo codice dove preferiamo nel corpo della pagina HTML o ad esempio nella @section Scripts di una view Razor.
<script src="https://cdn.jsdelivr.net/npm/@aspnet/signalr@1.1.4/dist/browser/signalr.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/msgpack5@4.2.1/dist/msgpack5.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@aspnet/signalr-protocol-msgpack@1.1.0/dist/browser/signalr-protocol-msgpack.min.js"></script>
Ora che abbiamo referenziato i file necessari, aggiungiamo di seguito il JavaScript per configurare la connessione all'hub di ASP.NET Core SignalR.
<script> const connection = new signalR.HubConnectionBuilder() .withUrl("/image-stream") //Url del nostro hub SignalR (spiegato nel precedente articolo) .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) //Usiamo il protocollo binario basato su MessagePack .build(); </script>
Ora dobbiamo registrarci per ricevere i messaggi 'ReceiveImage' inviati dal server. Nel farlo, indichiamo una funzione di callback che verrà automaticamente invocata ogni volta che il server invia una nuova immagine da visualizzare. La callback riceve i dati binari in forma di Uint8Array (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array), un oggetto JavaScript che rappresenta un array di byte.
Ottenuto l'array di byte potremmo certamente leggerne il contenuto come un comune array. Nel nostro caso, dato che abbiamo a che fare con delle immagini, si pone il problema di come visualizzarle nella pagina web. A tale scopo dobbiamo incapsulare l'array di byte in un oggetto Blob (https://developer.mozilla.org/en-US/docs/Web/API/Blob) da cui potremo ottenere un percorso assegnabile alla proprietà src di un elemento img.
<script> let previousObjectURL; connection.on('ReceiveImage', data => { //La variabile data è di tipo Uint8Array //Creo un blob a partire dai dati binari che ho ricevuto const blob = new Blob([data], {type: "image/png"}); //Creo un percorso al Blob e lo assegno alla proprietà src di un elemento img const currentObjectURL = URL.createObjectURL(blob); document.getElementById('targetImage').src = currentObjectURL; //Dealloco l'URL generato precedentemente, così da evitare dei memory leak. if (previousObjectURL) { URL.revokeObjectURL(previousObjectURL); } //Conservo il riferimento all'URL che ho generato poco fa, così che lo si possa deallocare poi previousObjectURL = currentObjectURL; }); </script>
Ora siamo pronti per stabilire una connessione all'hub di ASP.NET Core SignalR. A quel punto cominceremo a ricevere le immagini dal server.
<script> connection.start(); </script>
Non dimentichiamo di aggiungere alla pagina l'elemento img che visualizzerà le immagini. Il suo attributo src può essere inizializzato con un'immagine qualsiasi, perché poi verrà riassegnato con i percorsi ai Blob creati di volta in volta.
<img id="targetImage" src="/blank.gif" width="200" height="200">
Provare il funzionamento
Se avviamo l'applicazione, vedremo una nuova immagine apparire ogni secondo. Andando a curiosare nella scheda "Network" o "Rete" degli strumenti di sviluppo del browser (tasto F12), vedremo apparire tante richieste, una per ogni immagine mostrata. Come si vede qui, il browser crea i percorsi ai Blob con un formato particolare, contenente un codice che lo aiuta a identificare univocamente la risorsa binaria presente in memoria.
Inoltre, se usiamo un web debugger come Fiddler, vedremo che i dati binari sono traferiti tali e quali, senza alcuna codifica Base64, dato che MessagePack è appunto un protocollo che supporta il trasferimento binario.
Conclusioni
Grazie ad ASP.NET Core SignalR e al trasporto MessagePack, abbiamo visto come trasferire dati binari da server a client in tempo reale. Lo stesso protocollo può essere usato anche per inviare dati testuali.Il codice presentato in questo script si trova su GitHub, nel seguente repository.
https://github.com/aspitalia/aspnetcore-signalr-binary
Nel ramo start-stop dello stesso repository si trova anche un'implementazione minimale della funzionalità di avvio e arresto che consente ai client di decidere quando ricevere i contenuti binari dal server. In questo modo, l'invio è ottimizzato perché avviene solo quando ci sono client connessi.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Usare lo spread operator con i collection initializer in C#
Persistere la ChatHistory di Semantic Kernel in ASP.NET Core Web API per GPT
Effettuare il log delle chiamate a function di GPT in ASP.NET Web API
Migliorare i tempi di risposta di GPT tramite lo streaming endpoint in ASP.NET Core
Assegnare un valore di default a un parametro di una lambda in C#
Cancellare una run di un workflow di GitHub
Recuperare l'ultima versione di una release di GitHub
Cambiare la chiave di partizionamento di Azure Cosmos DB
Eseguire operazioni sui blob con Azure Storage Actions
Utilizzare un numero per gestire la concorrenza ottimistica con SQL Server ed Entity Framework
Effettuare il binding di date in Blazor
Registrare servizi multipli tramite chiavi in ASP.NET Core 8