Zelfstudie: Berichten publiceren en abonneren tussen WebSocket-clients met behulp van subprotocol

In de zelfstudie Een chat-app bouwen hebt u geleerd hoe u WebSocket-API's gebruikt om gegevens te verzenden en te ontvangen met Azure Web PubSub. U kunt zien dat er geen protocol nodig is wanneer de client communiceert met de service. U kunt bijvoorbeeld elk type gegevens verzenden met behulp WebSocket.send()van en de server ontvangt deze op dezelfde manier. WebSocket-API's zijn eenvoudig te gebruiken, maar de functionaliteit is beperkt. U kunt bijvoorbeeld niet de naam van de gebeurtenis opgeven bij het verzenden van de gebeurtenis naar uw server of het bericht publiceren naar andere clients in plaats van deze naar uw server te verzenden. In deze zelfstudie leert u hoe u subprotocol gebruikt om de functionaliteit van de client uit te breiden.

In deze zelfstudie leert u het volgende:

  • Een Web PubSub-service-exemplaar maken
  • Genereer de volledige URL om de WebSocket-verbinding tot stand te brengen
  • Berichten publiceren tussen WebSocket-clients met behulp van subprotocol

Als u geen Azure-abonnement hebt, kunt u een gratis Azure-account maken voordat u begint.

Vereisten

  • Voor deze installatie is versie 2.22.0 of hoger van de Azure CLI vereist. Als u Azure Cloud Shell gebruikt, is de nieuwste versie al geïnstalleerd.

Een Azure Web PubSub-exemplaar maken

Een brongroep maken

Een resourcegroep is een logische container waarin Azure-resources worden geïmplementeerd en beheerd. Gebruik de opdracht az group create om een resourcegroep te maken met de naam myResourceGroup op de eastus locatie.

az group create --name myResourceGroup --location EastUS

Een Web PubSub-exemplaar maken

Voer az extension add uit om de webpubsub-extensie te installeren of bij te werken naar de huidige versie.

az extension add --upgrade --name webpubsub

Gebruik de azure CLI az webpubsub create command om een Web PubSub te maken in de resourcegroep die u hebt gemaakt. Met de volgende opdracht maakt u een gratis Web PubSub-resource onder resourcegroep myResourceGroup in EastUS:

Belangrijk

Elke Web PubSub-resource moet een unieke naam hebben. Vervang <uw unieke resourcenaam> door de naam van uw Web PubSub in de volgende voorbeelden.

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

In de uitvoer van deze opdracht ziet u eigenschappen van de zojuist gemaakte resource. Let op de onderstaande twee eigenschappen:

  • Resourcenaam: de naam die u hebt opgegeven voor de --name bovenstaande parameter.
  • hostName: In het voorbeeld is <your-unique-resource-name>.webpubsub.azure.com/de hostnaam .

Op dit moment is uw Azure-account de enige die gemachtigd is om bewerkingen uit te voeren op deze nieuwe resource.

De Verbinding maken ionString ophalen voor toekomstig gebruik

Belangrijk

Een verbindingsreeks bevat de autorisatiegegevens die nodig zijn voor uw toepassing voor toegang tot de Azure Web PubSub-service. De toegangssleutel in de verbindingsreeks is vergelijkbaar met een hoofdwachtwoord voor uw service. In productieomgevingen moet u altijd voorzichtig zijn met het beveiligen van uw toegangssleutels. Gebruik Azure Key Vault om uw sleutels veilig te beheren en te roteren. Vermijd het distribueren van toegangssleutels naar andere gebruikers, het coderen ervan of het opslaan van ze ergens in tekst zonder opmaak die toegankelijk is voor anderen. Draai uw sleutels als u denkt dat ze mogelijk zijn aangetast.

Gebruik de opdracht Azure CLI az webpubsub key om de Verbinding maken ionString van de service op te halen. Vervang de <your-unique-resource-name> tijdelijke aanduiding door de naam van uw Azure Web PubSub-exemplaar.

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

Kopieer de verbindingsreeks om later te gebruiken.

Kopieer de opgehaalde Verbinding maken ionString en gebruik deze later in deze zelfstudie als de waarde van <connection_string>.

Het project instellen

Vereisten

Een subprotocol gebruiken

De client kan een WebSocket-verbinding starten met behulp van een specifiek subprotocol. De Azure Web PubSub-service ondersteunt een subprotocol dat wordt aangeroepen json.webpubsub.azure.v1 om clients in staat te stellen rechtstreeks via de Web PubSub-service te publiceren/abonneren in plaats van een retour naar de upstream-server. Controleer het door Azure Web PubSub ondersteunde JSON WebSocket-subprotocol voor meer informatie over het subprotocol.

Als u andere protocolnamen gebruikt, worden deze genegeerd door de service en passthrough naar de server in de gebeurtenis-handler voor verbinding, zodat u uw eigen protocollen kunt bouwen.

We gaan nu een webtoepassing maken met behulp van het json.webpubsub.azure.v1 subprotocol.

  1. Afhankelijkheden installeren

    mkdir logstream
    cd logstream
    dotnet new web
    dotnet add package Microsoft.Extensions.Azure
    dotnet add package Azure.Messaging.WebPubSub
    
  2. Maak de serverzijde om de /negotiate API en webpagina te hosten.

    Werk Program.cs bij met de onderstaande code.

    • Gebruik AddAzureClients dit om de serviceclient toe te voegen en de verbindingsreeks uit de configuratie te lezen.
    • Voeg app.UseStaticFiles(); toe voordat app.Run(); u statische bestanden ondersteunt.
    • En werk app.MapGet bij om het clienttoegangstoken met /negotiate aanvragen te genereren.
    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. De webpagina maken

    Maak een HTML-pagina met onderstaande inhoud en sla deze op als 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>                                                                
    

    De bovenstaande code maakt verbinding met de service en drukt een bericht af dat op de pagina is ontvangen. De belangrijkste wijziging is dat we het subprotocol opgeven bij het maken van de WebSocket-verbinding.

  4. De server uitvoeren

    We gebruiken het hulpprogramma Secret Manager voor .NET Core om de verbindingsreeks in te stellen. Voer de onderstaande opdracht uit, vervang deze door <connection_string> de opdracht die u in de vorige stap hebt opgehaald en open http://localhost:5000/index.html deze in de browser:

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

    Als u Chrome gebruikt, kunt u op F12 drukken of met de rechtermuisknop op ->Inspect ->Developer Tools klikken en het tabblad Netwerk selecteren. Laad de webpagina en u kunt zien dat de WebSocket-verbinding tot stand is gebracht. Selecteer deze optie om de WebSocket-verbinding te inspecteren. Hieronder ziet u het onderstaande connected gebeurtenisbericht wordt ontvangen in de client. U kunt zien dat u de connectionId gegenereerde client kunt ophalen.

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

U kunt zien dat u met behulp van subprotocol enkele metagegevens van de verbinding kunt ophalen wanneer de verbinding is connected.

De client ontvangt nu een JSON-bericht in plaats van een tekst zonder opmaak. JSON-bericht bevat meer informatie, zoals het type en de bron van het bericht. U kunt deze informatie dus gebruiken om meer verwerking voor het bericht uit te voeren (bijvoorbeeld het bericht weergeven in een andere stijl als het afkomstig is van een andere bron), die u in latere secties kunt vinden.

Berichten van client publiceren

Wanneer de client in de zelfstudie Een chat-app bouwen een bericht verzendt via een WebSocket-verbinding met de Web PubSub-service, activeert de service een gebruikersevenement aan de serverzijde. Met subprotocol heeft de client meer functionaliteiten door een JSON-bericht te verzenden. U kunt bijvoorbeeld berichten rechtstreeks vanuit de client publiceren via de Web PubSub-service naar andere clients.

Dit is handig als u in realtime een grote hoeveelheid gegevens naar andere clients wilt streamen. We gaan deze functie gebruiken om een logboekstreamingtoepassing te bouwen, waarmee consolelogboeken in realtime naar de browser kunnen worden gestreamd.

  1. Het streamingprogramma maken

    stream Een programma maken:

    mkdir stream
    cd stream
    dotnet new console
    

    Werk Program.cs bij met de volgende inhoud:

    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; }
            }
        }
    }
    
    

    Hier ziet u een nieuwe conceptgroep. Groep is logisch concept in een hub waar u een bericht kunt publiceren naar een groep verbindingen. In een hub kunt u meerdere groepen hebben en één client zich tegelijkertijd op meerdere groepen abonneren. Wanneer u subprotocol gebruikt, kunt u alleen publiceren naar een groep in plaats van naar de hele hub te uitzenden. Raadpleeg de basisconcepten voor meer informatie over de voorwaarden.

  2. Omdat we hier groep gebruiken, moeten we ook de webpagina index.html bijwerken om lid te worden van de groep wanneer de WebSocket-verbinding tot stand is gebracht binnen ws.onopen callback.

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

    U kunt zien dat de client lid wordt van de groep door een bericht in joinGroup het type te verzenden.

  3. Werk de ws.onmessage callbacklogica ook enigszins bij om het JSON-antwoord te parseren en de berichten alleen uit stream de groep af te drukken, zodat deze fungeert als livestreamprinter.

    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. Voor beveiligingsoverweging kan een client standaard niet zelf een groep publiceren of erop abonneren. U hebt dus gemerkt dat we zijn ingesteld roles op de client bij het genereren van het token:

    Stel de roles status in GenerateClientAccessUri zoals Startup.cs hieronder:

    service.GenerateClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" })
    
  5. Pas ten slotte ook wat stijl toe zodat index.html deze mooi wordt weergegeven.

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

Voer nu de onderstaande code uit en typ tekst en deze worden in realtime weergegeven in de browser:

ls -R | dotnet run

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

Of u maakt het langzamer, zodat u kunt zien dat de gegevens in realtime naar de browser worden gestreamd:

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

Hier vindt u het volledige codevoorbeeld van deze zelfstudie.

Volgende stappen

Deze zelfstudie biedt een basisidee van hoe u verbinding maakt met de Web PubSub-service en hoe u berichten publiceert naar de verbonden clients met behulp van subprotocol.

Bekijk andere zelfstudies voor meer informatie over het gebruik van de service.