Esercitazione: Pubblicare e sottoscrivere messaggi tra client WebSocket tramite protocollo secondario

Nell'esercitazione Creare un'app di chat si è appreso come usare le API WebSocket per inviare e ricevere dati con Web PubSub di Azure. Quando il client comunica con il servizio, non è necessario alcun protocollo. Ad esempio, è possibile inviare qualsiasi tipo di dati usando WebSocket.send()e il server lo riceve esattamente come è. Il processo delle API WebSocket è facile da usare, ma la funzionalità è limitata. Ad esempio, non è possibile specificare il nome dell'evento quando si invia l'evento al server o si pubblica il messaggio ad altri client anziché inviarlo al server. In questa esercitazione si apprenderà come usare il sottoprotocolo per estendere la funzionalità del client.

In questa esercitazione apprenderai a:

  • Creare un'istanza del servizio Web PubSub
  • Generare l'URL completo per stabilire la connessione WebSocket
  • Pubblicare messaggi tra client WebSocket usando il sottoprotocolo

Se non si ha una sottoscrizione di Azure, creare un account Azure gratuito prima di iniziare.

Prerequisiti

  • Questa configurazione richiede la versione 2.22.0 o successiva dell'interfaccia della riga di comando di Azure. Se si usa Azure Cloud Shell, la versione più recente è già installata.

Creare un'istanza di PubSub Di Azure

Creare un gruppo di risorse

Un gruppo di risorse è un contenitore logico in cui vengono distribuite e gestite le risorse di Azure. Usare il comando az group create per creare un gruppo di risorse denominato myResourceGroup nel eastus percorso.

az group create --name myResourceGroup --location EastUS

Creare un'istanza di Web PubSub

Eseguire az extension add per installare o aggiornare l'estensione webpubsub alla versione corrente.

az extension add --upgrade --name webpubsub

Usare il comando az webpubsub create dell'interfaccia della riga di comando di Azure per creare un Web PubSub nel gruppo di risorse creato. Il comando seguente crea una risorsa Web PubSub gratuita nel gruppo di risorse myResourceGroup in EastUS:

Importante

Ogni risorsa Web PubSub deve avere un nome univoco. Sostituire <your-unique-resource-name> con il nome di Web PubSub negli esempi seguenti.

az webpubsub create --name "<your-unique-resource-name>" --resource-group "myResourceGroup" --location "EastUS" --sku Free_F1

L'output di questo comando mostra le proprietà della risorsa appena creata. Prendere nota delle due proprietà elencate di seguito:

  • Nome risorsa: nome specificato al --name parametro precedente.
  • hostName: nell'esempio il nome host è <your-unique-resource-name>.webpubsub.azure.com/.

A questo punto, l'account Azure è l'unico autorizzato a eseguire qualsiasi operazione su questa nuova risorsa.

Ottenere il Connessione ionString per un uso futuro

Importante

Un stringa di connessione include le informazioni di autorizzazione necessarie per l'applicazione per accedere al servizio Web PubSub di Azure. La chiave di accesso all'interno del stringa di connessione è simile a una password radice per il servizio. Negli ambienti di produzione, prestare sempre attenzione a proteggere le chiavi di accesso. Usare Azure Key Vault per gestire e ruotare le chiavi in modo sicuro. Evitare di distribuire chiavi di accesso ad altri utenti, hardcodedarli o salvarli in qualsiasi punto del testo normale accessibile ad altri utenti. Ruotare le chiavi se si ritiene che siano state compromesse.

Usare il comando az webpubsub key dell'interfaccia della riga di comando di Azure per ottenere il Connessione ionString del servizio. Sostituire il <your-unique-resource-name> segnaposto con il nome dell'istanza di PubSub Web di Azure.

az webpubsub key show --resource-group myResourceGroup --name <your-unique-resource-name> --query primaryConnectionString --output tsv

Copiare il stringa di connessione da usare in un secondo momento.

Copiare il Connessione ionString recuperato e usarlo più avanti in questa esercitazione come valore di <connection_string>.

Configurare il progetto

Prerequisiti

Uso di un sottoprotocolo

Il client può avviare una connessione WebSocket usando un sottoprotocolo specifico. Il servizio Web PubSub di Azure supporta un sottoprotocolo chiamato json.webpubsub.azure.v1 per consentire ai client di pubblicare/sottoscrivere direttamente tramite il servizio Web PubSub anziché un round trip al server upstream. Per informazioni dettagliate sul sottoprotocolo del sottoprotocolo JSON WebSocket supportato, vedere Web PubSub di Azure.

Se si usano altri nomi di protocollo, questi verranno ignorati dal servizio e dal pass-through al server nel gestore eventi di connessione, in modo da poter creare protocolli personalizzati.

A questo punto si creerà un'applicazione Web usando il json.webpubsub.azure.v1 sottoprotocolo.

  1. Installare le dipendenze

    mkdir logstream
    cd logstream
    dotnet new web
    dotnet add package Microsoft.Extensions.Azure
    dotnet add package Azure.Messaging.WebPubSub
    
  2. Creare il lato server per ospitare l'API e la /negotiate pagina Web.

    Eseguire l'aggiornamento Program.cs con il codice seguente.

    • Usare AddAzureClients per aggiungere il client del servizio e leggere il stringa di connessione dalla configurazione.
    • Aggiungere app.UseStaticFiles(); prima app.Run(); per supportare i file statici.
    • E aggiornare app.MapGet per generare il token di accesso client con /negotiate le richieste.
    using Azure.Messaging.WebPubSub;
    using Microsoft.Extensions.Azure;
    
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddAzureClients(s =>
    {
        s.AddWebPubSubServiceClient(builder.Configuration["Azure:WebPubSub:ConnectionString"], "stream");
    });
    
    var app = builder.Build();
    app.UseStaticFiles();
    app.MapGet("/negotiate", async context =>
    {
        var service = context.RequestServices.GetRequiredService<WebPubSubServiceClient>();
        var response = new
        {
            url = service.GetClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" }).AbsoluteUri
        };
        await context.Response.WriteAsJsonAsync(response);
    });
    
    app.Run();
    
  3. Creare la pagina Web

    Creare una pagina HTML con il contenuto seguente e salvarla come wwwroot/index.html:

    <html>
      <body>
        <div id="output"></div>
        <script>
          (async function () {
            let res = await fetch('/negotiate')
            let data = await res.json();
            let ws = new WebSocket(data.url, 'json.webpubsub.azure.v1');
            ws.onopen = () => {
              console.log('connected');
            };
    
            let output = document.querySelector('#output');
            ws.onmessage = event => {
              let d = document.createElement('p');
              d.innerText = event.data;
              output.appendChild(d);
            };
          })();
        </script>
      </body>
    </html>                                                                
    

    Il codice precedente si connette al servizio e stampa qualsiasi messaggio ricevuto nella pagina. La modifica principale consiste nel specificare il sottoprotocolo durante la creazione della connessione WebSocket.

  4. Eseguire il server

    Lo strumento Secret Manager per .NET Core viene usato per impostare il stringa di connessione. Eseguire il comando seguente, sostituendo <connection_string> con quello recuperato nel passaggio precedente e aperto http://localhost:5000/index.html nel browser:

    dotnet user-secrets init
    dotnet user-secrets set Azure:WebPubSub:ConnectionString "<connection-string>"
    dotnet run
    

    Se si usa Chrome, è possibile premere F12 o fare clic con il pulsante destro del mouse su ->Inspect ->Developer Tools e selezionare la scheda Rete . Caricare la pagina Web ed è possibile visualizzare che viene stabilita la connessione WebSocket. Selezionare questa opzione per esaminare la connessione WebSocket. È possibile visualizzare il messaggio di evento seguente connected ricevuto nel client. È possibile vedere che è possibile ottenere il connectionId generato per questo client.

    {"type":"system","event":"connected","userId":null,"connectionId":"<the_connection_id>"}
    

È possibile osservare che con l'aiuto del sottoprotocolo è possibile ottenere alcuni metadati della connessione quando la connessione è connected.

Il client riceve ora un messaggio JSON anziché un testo normale. Il messaggio JSON contiene altre informazioni, ad esempio il tipo e l'origine del messaggio. È quindi possibile usare queste informazioni per eseguire un'elaborazione maggiore al messaggio (ad esempio, visualizzare il messaggio in uno stile diverso se proviene da un'origine diversa), che è possibile trovare nelle sezioni successive.

Pubblicare messaggi dal client

Nell'esercitazione Creare un'app di chat, quando il client invia un messaggio tramite connessione WebSocket al servizio Web PubSub, il servizio attiva un evento utente sul lato server. Con il sottoprotocolo, il client ha più funzionalità inviando un messaggio JSON. Ad esempio, è possibile pubblicare messaggi direttamente dal client tramite il servizio Web PubSub ad altri client.

Ciò è utile se si vuole trasmettere una grande quantità di dati ad altri client in tempo reale. Si userà questa funzionalità per creare un'applicazione di streaming di log, che può trasmettere i log della console al browser in tempo reale.

  1. Creazione del programma di streaming

    Creare un stream programma:

    mkdir stream
    cd stream
    dotnet new console
    

    Aggiornare Program.cs con il contenuto seguente:

    using System;
    using System.Net.Http;
    using System.Net.WebSockets;
    using System.Text;
    using System.Text.Json;
    using System.Threading.Tasks;
    
    namespace stream
    {
        class Program
        {
            private static readonly HttpClient http = new HttpClient();
            static async Task Main(string[] args)
            {
                // Get client url from remote
                var stream = await http.GetStreamAsync("http://localhost:5000/negotiate");
                var url = (await JsonSerializer.DeserializeAsync<ClientToken>(stream)).url;
                var client = new ClientWebSocket();
                client.Options.AddSubProtocol("json.webpubsub.azure.v1");
    
                await client.ConnectAsync(new Uri(url), default);
    
                Console.WriteLine("Connected.");
                var streaming = Console.ReadLine();
                while (streaming != null)
                {
                    if (!string.IsNullOrEmpty(streaming))
                    {
                        var message = JsonSerializer.Serialize(new
                        {
                            type = "sendToGroup",
                            group = "stream",
                            data = streaming + Environment.NewLine,
                        });
                        Console.WriteLine("Sending " + message);
                        await client.SendAsync(Encoding.UTF8.GetBytes(message), WebSocketMessageType.Text, true, default);
                    }
    
                    streaming = Console.ReadLine();
                }
    
                await client.CloseAsync(WebSocketCloseStatus.NormalClosure, null, default);
            }
    
            private sealed class ClientToken
            {
                public string url { get; set; }
            }
        }
    }
    
    

    Qui è disponibile un nuovo concetto "gruppo". Il gruppo è un concetto logico in un hub in cui è possibile pubblicare messaggi in un gruppo di connessioni. In un hub è possibile avere più gruppi e un client può sottoscrivere più gruppi contemporaneamente. Quando si usa il sottoprotocolo, è possibile pubblicare solo in un gruppo anziché trasmettere all'intero hub. Per informazioni dettagliate sui termini, vedere i concetti di base.

  2. Poiché in questo caso viene usato il gruppo, è anche necessario aggiornare la pagina index.html Web per partecipare al gruppo quando viene stabilita la connessione WebSocket all'interno ws.onopen del callback.

    let ackId = 0;
    ws.onopen = () => {
      console.log('connected');
      ws.send(JSON.stringify({
        type: 'joinGroup',
        group: 'stream',
        ackId: ++ackId
      }));
    };
    

    È possibile visualizzare l'aggiunta del client al gruppo inviando un messaggio di joinGroup tipo .

  3. Aggiornare anche leggermente la ws.onmessage logica di callback per analizzare la risposta JSON e stampare i messaggi solo dal stream gruppo in modo che funzioni come stampante di flusso live.

    ws.onmessage = event => {
      let message = JSON.parse(event.data);
      if (message.type === 'message' && message.group === 'stream') {
        let d = document.createElement('span');
        d.innerText = message.data;
        output.appendChild(d);
        window.scrollTo(0, document.body.scrollHeight);
      }
    };
    
  4. Per considerazioni sulla sicurezza, per impostazione predefinita un client non può pubblicare o sottoscrivere un gruppo da solo. Si è quindi notato che è stato impostato roles sul client durante la generazione del token:

    Impostare quando rolesGenerateClientAccessUri in, come illustrato di Startup.cs seguito:

    service.GenerateClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" })
    
  5. Infine applicare anche uno stile a index.html in modo che venga visualizzato bene.

    <html>
    
      <head>
        <style>
          #output {
            white-space: pre;
            font-family: monospace;
          }
        </style>
      </head>
    

Eseguire ora il codice seguente e digitare qualsiasi testo e visualizzato nel browser in tempo reale:

ls -R | dotnet run

# Or call `dir /s /b | dotnet run` when you are using CMD under Windows

In alternativa, è più lento in modo da poter vedere che i dati vengono trasmessi al browser in tempo reale:

for i in $(ls -R); do echo $i; sleep 0.1; done | dotnet run

L'esempio di codice completo di questa esercitazione è disponibile qui.

Passaggi successivi

Questa esercitazione offre un'idea di base su come connettersi al servizio Web PubSub e su come pubblicare messaggi nei client connessi usando il sottoprotocolo.

Vedere altre esercitazioni per approfondire l'uso del servizio.