Delen via


Zelfstudie: Een chat-app maken met de Azure Web PubSub-service

In de zelfstudie Berichten publiceren en abonneren leert u de basisprincipes van het publiceren en abonneren van berichten met Azure Web PubSub. In deze zelfstudie leert u het gebeurtenissysteem van Azure Web PubSub en gebruikt u dit om een volledige webtoepassing te bouwen met realtime communicatiefunctionaliteit.

In deze zelfstudie leert u het volgende:

  • Een Web PubSub-service-exemplaar maken
  • Instellingen voor gebeurtenis-handler configureren voor Azure Web PubSub
  • Gebeurtenissen in de app-server afhandelen en een realtime chat-app bouwen

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.

ConnectionString ophalen voor toekomstig gebruik

Belangrijk

Onbewerkte verbindingsreeks worden alleen in dit artikel weergegeven voor demonstratiedoeleinden.

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. Beveilig uw toegangssleutels altijd in productieomgevingen. Gebruik Azure Key Vault om uw sleutels veilig te beheren en te roteren en uw verbinding te beveiligen.WebPubSubServiceClient

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 azure CLI az webpubsub key command om de ConnectionString 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 ConnectionString en stel deze in in de omgevingsvariabeleWebPubSubConnectionString, die later wordt gelezen in de zelfstudie. Vervang <connection-string> hieronder door de ConnectionString die u hebt opgehaald.

export WebPubSubConnectionString="<connection-string>"
SET WebPubSubConnectionString=<connection-string>

Het project instellen

Vereisten

De toepassing maken

In Azure Web PubSub zijn er twee functies, server en client. Dit concept is vergelijkbaar met de server- en clientrollen in een webtoepassing. Server is verantwoordelijk voor het beheren van de clients, luisteren en reageren op clientberichten. De client is verantwoordelijk voor het verzenden en ontvangen van berichten van de gebruiker van de server en visualiseert deze voor de eindgebruiker.

In deze zelfstudie bouwen we een realtime-webtoepassing voor chats. In een echte webtoepassing omvat de verantwoordelijkheid van de server ook het verifiëren van clients en het leveren van statische webpagina's voor de gebruikersinterface van de toepassing.

We gebruiken ASP.NET Core 8 om de webpagina's te hosten en binnenkomende aanvragen te verwerken.

Laten we eerst een ASP.NET Core-web-app maken in een chatapp map.

  1. Maak een nieuwe web-app.

    mkdir chatapp
    cd chatapp
    dotnet new web
    
  2. Voeg Program.cs toe app.UseStaticFiles() ter ondersteuning van het hosten van statische webpagina's.

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    
    app.UseStaticFiles();
    
    app.Run();
    
  3. Maak een HTML-bestand en sla het op als wwwroot/index.html, we gebruiken het voor de gebruikersinterface van de chat-app later.

    <html>
      <body>
        <h1>Azure Web PubSub Chat</h1>
      </body>
    </html>
    

U kunt de server testen door deze uit te voeren dotnet run --urls http://localhost:8080 en te openen http://localhost:8080/index.html in de browser.

Onderhandelingseindpunt toevoegen

In de zelfstudie Publiceren en abonneren gebruikt de abonnee verbindingsreeks rechtstreeks. In een echte toepassing is het niet veilig om de verbindingsreeks te delen met een client, omdat verbindingsreeks hoge bevoegdheden heeft om bewerkingen voor de service uit te voeren. Laten we nu uw server de verbindingsreeks laten gebruiken en een negotiate eindpunt beschikbaar maken voor de client om de volledige URL met toegangstoken op te halen. Op deze manier kan de server verificatie-middleware toevoegen vóór het negotiate eindpunt om onbevoegde toegang te voorkomen.

Installeer eerst de afhankelijkheden.

dotnet add package Microsoft.Azure.WebPubSub.AspNetCore

We gaan nu een /negotiate eindpunt toevoegen voor de client om het token te genereren.

using Azure.Core;
using Microsoft.Azure.WebPubSub.AspNetCore;
using Microsoft.Azure.WebPubSub.Common;
using Microsoft.Extensions.Primitives;

// Read connection string from environment
var connectionString = Environment.GetEnvironmentVariable("WebPubSubConnectionString");
if (connectionString == null)
{
    throw new ArgumentNullException(nameof(connectionString));
}

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddWebPubSub(o => o.ServiceEndpoint = new WebPubSubServiceEndpoint(connectionString))
    .AddWebPubSubServiceClient<Sample_ChatApp>();
var app = builder.Build();

app.UseStaticFiles();

// return the Client Access URL with negotiate endpoint
app.MapGet("/negotiate", (WebPubSubServiceClient<Sample_ChatApp> service, HttpContext context) =>
{
    var id = context.Request.Query["id"];
    if (StringValues.IsNullOrEmpty(id))
    {
        context.Response.StatusCode = 400;
        return null;
    }
    return new
    {
        url = service.GetClientAccessUri(userId: id).AbsoluteUri
    };
});
app.Run();

sealed class Sample_ChatApp : WebPubSubHub
{
}

AddWebPubSubServiceClient<THub>() wordt gebruikt om de serviceclient WebPubSubServiceClient<THub>te injecteren, waarmee we in de onderhandelingsstap een clientverbindingstoken en in hubmethoden kunnen genereren om service REST API's aan te roepen wanneer hubgebeurtenissen worden geactiveerd. Deze code voor het genereren van tokens is vergelijkbaar met de code die we hebben gebruikt in de zelfstudie voor het publiceren en abonneren van berichten, behalve dat we nog één argument (userId) doorgeven bij het genereren van het token. Gebruikers-id kan worden gebruikt om de identiteit van de client te identificeren, dus wanneer u een bericht ontvangt waarvan u weet waar het bericht vandaan komt.

De code leest verbindingsreeks uit de omgevingsvariabele WebPubSubConnectionString die we in de vorige stap hebben ingesteld.

Voer de server opnieuw uit met behulp van dotnet run --urls http://localhost:8080.

U kunt deze API testen door toegang te krijgen http://localhost:8080/negotiate?id=user1 en u krijgt de volledige URL van de Azure Web PubSub met een toegangstoken.

Gebeurtenissen verwerken

Wanneer er in Azure Web PubSub bepaalde activiteiten plaatsvinden aan de clientzijde (bijvoorbeeld wanneer een client verbinding maakt, verbonden, verbroken of een client berichten verzendt), verzendt de service meldingen naar de server, zodat deze op deze gebeurtenissen kan reageren.

Gebeurtenissen worden geleverd aan de server in de vorm van Webhook. Webhook wordt geleverd en weergegeven door de toepassingsserver en geregistreerd aan de azure Web PubSub-servicezijde. De service roept de webhooks aan wanneer er een gebeurtenis plaatsvindt.

Azure Web PubSub volgt CloudEvents om de gebeurtenisgegevens te beschrijven.

Hieronder verwerken connected we systeem gebeurtenissen wanneer een client is verbonden en verwerken message gebruikers gebeurtenissen wanneer een client berichten verzendt om de chat-app te bouwen.

De Web PubSub SDK voor AspNetCore Microsoft.Azure.WebPubSub.AspNetCore die we in de vorige stap hebben geïnstalleerd, kan ook helpen bij het parseren en verwerken van de CloudEvents-aanvragen.

Voeg eerst gebeurtenis-handlers toe voordat app.Run(). Geef het eindpuntpad voor de gebeurtenissen op, laten we zeggen /eventhandler.

app.MapWebPubSubHub<Sample_ChatApp>("/eventhandler/{*path}");
app.Run();

Voeg nu in de klasse Sample_ChatApp die we in de vorige stap hebben gemaakt, een constructor toe om mee WebPubSubServiceClient<Sample_ChatApp> te werken dat we gebruiken om de Web PubSub-service aan te roepen. En OnConnectedAsync() om te reageren wanneer connected een gebeurtenis wordt geactiveerd, OnMessageReceivedAsync() om berichten van de client te verwerken.

sealed class Sample_ChatApp : WebPubSubHub
{
    private readonly WebPubSubServiceClient<Sample_ChatApp> _serviceClient;

    public Sample_ChatApp(WebPubSubServiceClient<Sample_ChatApp> serviceClient)
    {
        _serviceClient = serviceClient;
    }

    public override async Task OnConnectedAsync(ConnectedEventRequest request)
    {
        Console.WriteLine($"[SYSTEM] {request.ConnectionContext.UserId} joined.");
    }

    public override async ValueTask<UserEventResponse> OnMessageReceivedAsync(UserEventRequest request, CancellationToken cancellationToken)
    {
        await _serviceClient.SendToAllAsync(RequestContent.Create(
        new
        {
            from = request.ConnectionContext.UserId,
            message = request.Data.ToString()
        }),
        ContentType.ApplicationJson);

        return new UserEventResponse();
    }
}

In de bovenstaande code gebruiken we de serviceclient om een meldingsbericht in JSON-indeling uit te zenden naar iedereen met wie lid is SendToAllAsync.

De webpagina bijwerken

Nu gaan we bijwerken index.html om de logica toe te voegen om verbinding te maken, bericht te verzenden en ontvangen berichten weer te geven op de pagina.

<html>
  <body>
    <h1>Azure Web PubSub Chat</h1>
    <input id="message" placeholder="Type to chat...">
    <div id="messages"></div>
    <script>
      (async function () {
        let id = prompt('Please input your user name');
        let res = await fetch(`/negotiate?id=${id}`);
        let data = await res.json();
        let ws = new WebSocket(data.url);
        ws.onopen = () => console.log('connected');

        let messages = document.querySelector('#messages');
        
        ws.onmessage = event => {
          let m = document.createElement('p');
          let data = JSON.parse(event.data);
          m.innerText = `[${data.type || ''}${data.from || ''}] ${data.message}`;
          messages.appendChild(m);
        };

        let message = document.querySelector('#message');
        message.addEventListener('keypress', e => {
          if (e.charCode !== 13) return;
          ws.send(message.value);
          message.value = '';
        });
      })();
    </script>
  </body>

</html>

U kunt in de bovenstaande code zien dat we verbinding maken met behulp van de systeemeigen WebSocket-API in de browser en gebruiken WebSocket.send() om berichten te verzenden en WebSocket.onmessage te luisteren naar ontvangen berichten.

U kunt ook client-SDK's gebruiken om verbinding te maken met de service, zodat u automatisch opnieuw verbinding kunt maken, foutafhandeling en meer.

Er is nu nog één stap over om de chat te laten werken. Laten we configureren naar welke gebeurtenissen we belangrijk zijn en waar de gebeurtenissen naartoe moeten worden verzonden in de Web PubSub-service.

De gebeurtenis-handler instellen

We stellen de gebeurtenis-handler in de Web PubSub-service in om de service te laten weten waar de gebeurtenissen naartoe moeten worden verzonden.

Wanneer de webserver lokaal wordt uitgevoerd, hoe de Web PubSub-service de localhost aanroept als deze geen eindpunt heeft dat toegankelijk is voor internet? Er zijn meestal twee manieren. De ene is om localhost openbaar te maken met behulp van een algemeen tunnelhulpprogramma en de andere is om awps-tunnel te gebruiken om het verkeer van de Web PubSub-service via het hulpprogramma naar uw lokale server te tunnelen.

In deze sectie gebruiken we Azure CLI om de gebeurtenis-handlers in te stellen en awps-tunnel te gebruiken om verkeer naar localhost te routeren.

Hubinstellingen configureren

We stellen de URL-sjabloon tunnel zodanig in dat Web PubSub berichten doorstuurt via de awps-tunneltunnelverbinding. Gebeurtenis-handlers kunnen worden ingesteld vanuit de portal of de CLI, zoals beschreven in dit artikel. Hier stellen we deze in via CLI. Omdat we gebeurtenissen in pad /eventhandler luisteren als de vorige stappenets, stellen we de URL-sjabloon in op tunnel:///eventhandler.

Gebruik de azure CLI az webpubsub hub create command om de instellingen voor de gebeurtenis-handler voor de Sample_ChatApp hub te maken.

Belangrijk

Vervang <uw unieke resourcenaam door de naam van uw Web PubSub-resource> die u in de vorige stappen hebt gemaakt.

az webpubsub hub create -n "<your-unique-resource-name>" -g "myResourceGroup" --hub-name "Sample_ChatApp" --event-handler url-template="tunnel:///eventhandler" user-event-pattern="*" system-event="connected"

Awps-tunnel lokaal uitvoeren

Awps-tunnel downloaden en installeren

Het hulpprogramma wordt uitgevoerd op Node.js versie 16 of hoger.

npm install -g @azure/web-pubsub-tunnel-tool

De service verbindingsreeks gebruiken en uitvoeren

export WebPubSubConnectionString="<your connection string>"
awps-tunnel run --hub Sample_ChatApp --upstream http://localhost:8080

De webserver uitvoeren

Nu is alles ingesteld. We voeren de webserver uit en spelen met de chat-app in actie.

Voer nu de server uit met behulp van dotnet run --urls http://localhost:8080.

Hier vindt u het volledige codevoorbeeld van deze zelfstudie.

http://localhost:8080/index.html openen. U kunt uw gebruikersnaam invoeren en chatten.

Luie verificatie met connect gebeurtenis-handler

In de vorige secties laten we zien hoe u een onderhandelingseindpunt gebruikt om de URL van de Web PubSub-service en het JWT-toegangstoken te retourneren voor de clients om verbinding te maken met de Web PubSub-service. In sommige gevallen, bijvoorbeeld edge-apparaten met beperkte resources, kunnen clients de voorkeur geven aan directe verbinding met Web PubSub-resources. In dergelijke gevallen kunt u de gebeurtenishandler configureren voor luie verificatie van de clients, gebruikers-id toewijzen aan de clients, de groepen opgeven waaraan de clients deelnemen zodra ze verbinding maken, de machtigingen configureren connect die de clients hebben en WebSocket-subprotocol als het WebSocket-antwoord op de client, enzovoort. Details verwijzen naar de specificatie van de gebeurtenis-handler verbinden.

We gaan nu de gebeurtenis-handler gebruiken connect om hetzelfde te bereiken als wat de sectie onderhandelen doet.

Hubinstellingen bijwerken

Eerst gaan we hubinstellingen bijwerken om ook gebeurtenis-handler op te nemen connect . We moeten ook anonieme verbinding toestaan, zodat clients zonder JWT-toegangstoken verbinding kunnen maken met de service.

Gebruik de azure CLI az webpubsub hub update command to create the event handler settings for the Sample_ChatApp hub.

Belangrijk

Vervang <uw unieke resourcenaam door de naam van uw Web PubSub-resource> die u in de vorige stappen hebt gemaakt.

az webpubsub hub update -n "<your-unique-resource-name>" -g "myResourceGroup" --hub-name "Sample_ChatApp" --allow-anonymous true --event-handler url-template="tunnel:///eventhandler" user-event-pattern="*" system-event="connected" system-event="connect"

Upstreamlogica bijwerken om verbindingsbeurtenis af te handelen

Nu gaan we upstreamlogica bijwerken om verbindingsevenementen af te handelen. We kunnen nu ook het onderhandelingseindpunt verwijderen.

Net als wat we doen in het onderhandelingseindpunt als demodoel, lezen we ook de id van de queryparameters. In een verbindingsgebeurtenis blijft de oorspronkelijke clientquery behouden in de hoofdtekst van de aanvraag voor de verbindingsgebeurtenis.

Binnen de klasse Sample_ChatAppoverschrijven OnConnectAsync() voor het afhandelen connect van gebeurtenis:

sealed class Sample_ChatApp : WebPubSubHub
{
    private readonly WebPubSubServiceClient<Sample_ChatApp> _serviceClient;

    public Sample_ChatApp(WebPubSubServiceClient<Sample_ChatApp> serviceClient)
    {
        _serviceClient = serviceClient;
    }

    public override ValueTask<ConnectEventResponse> OnConnectAsync(ConnectEventRequest request, CancellationToken cancellationToken)
    {
        if (request.Query.TryGetValue("id", out var id))
        {
            return new ValueTask<ConnectEventResponse>(request.CreateResponse(userId: id.FirstOrDefault(), null, null, null));
        }

        // The SDK catches this exception and returns 401 to the caller
        throw new UnauthorizedAccessException("Request missing id");
    }

    public override async Task OnConnectedAsync(ConnectedEventRequest request)
    {
        Console.WriteLine($"[SYSTEM] {request.ConnectionContext.UserId} joined.");
    }

    public override async ValueTask<UserEventResponse> OnMessageReceivedAsync(UserEventRequest request, CancellationToken cancellationToken)
    {
        await _serviceClient.SendToAllAsync(RequestContent.Create(
        new
        {
            from = request.ConnectionContext.UserId,
            message = request.Data.ToString()
        }),
        ContentType.ApplicationJson);

        return new UserEventResponse();
    }
}

Index.html bijwerken om rechtstreeks verbinding te maken

Nu gaan we de webpagina bijwerken om rechtstreeks verbinding te maken met de Web PubSub-service. Een ding om te vermelden is dat het Web PubSub-service-eindpunt nu voor demodoeleinden is vastgelegd in de clientcode. Werk de hostnaam <the host name of your service> van de service in de onderstaande HTML bij met de waarde van uw eigen service. Het kan nog steeds nuttig zijn om de waarde van het Web PubSub-service-eindpunt op te halen van uw server, waardoor u meer flexibiliteit en controle hebt over de locatie waar de client verbinding mee maakt.

<html>
  <body>
    <h1>Azure Web PubSub Chat</h1>
    <input id="message" placeholder="Type to chat...">
    <div id="messages"></div>
    <script>
      (async function () {
        // sample host: mock.webpubsub.azure.com
        let hostname = "<the host name of your service>";
        let id = prompt('Please input your user name');
        let ws = new WebSocket(`wss://${hostname}/client/hubs/Sample_ChatApp?id=${id}`);
        ws.onopen = () => console.log('connected');

        let messages = document.querySelector('#messages');
        
        ws.onmessage = event => {
          let m = document.createElement('p');
          let data = JSON.parse(event.data);
          m.innerText = `[${data.type || ''}${data.from || ''}] ${data.message}`;
          messages.appendChild(m);
        };

        let message = document.querySelector('#message');
        message.addEventListener('keypress', e => {
          if (e.charCode !== 13) return;
          ws.send(message.value);
          message.value = '';
        });
      })();
    </script>
  </body>

</html>

De server opnieuw uitvoeren

Voer de server nu opnieuw uit en ga naar de webpagina volgens de instructies daarvoor. Als u bent gestopt awps-tunnel, voert u ook het tunnelhulpprogramma opnieuw uit.

Volgende stappen

Deze zelfstudie biedt een basisidee van de werking van het gebeurtenissysteem in de Azure Web PubSub-service.

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