Tutorial: Membuat aplikasi obrolan dengan layanan Azure Web PubSub

Dalam tutorial Menerbitkan dan berlangganan pesan, Anda mempelajari dasar-dasar penerbitan dan berlangganan pesan dengan Azure Web PubSub. Dalam tutorial ini, Anda mempelajari sistem peristiwa Azure Web PubSub dan menggunakannya untuk membangun aplikasi web lengkap dengan fungsionalitas komunikasi real-time.

Dalam tutorial ini, Anda akan mempelajari cara:

  • Membuat instans layanan Web PubSub
  • Mengonfigurasi pengaturan penanganan aktivitas untuk Azure Web PubSub
  • Peristiwa Hanlde di server aplikasi dan membangun aplikasi obrolan real time

Jika Anda tidak memiliki Langganan Azure, buat Akun gratis Azure sebelum memulai.

Prasyarat

  • Penyiapan ini memerlukan CLI Azure versi 2.22.0 atau lebih tinggi. Jika menggunakan Azure Cloud Shell, versi terbaru sudah terinstal.

Membuat instans Azure Web PubSub

Buat grup sumber daya

Grup sumber daya adalah kontainer logis yang disebarkan dan dikelola oleh sumber daya Azure. Gunakan perintah az group create untuk membuat grup sumber daya bernama myResourceGroup di eastus lokasi.

az group create --name myResourceGroup --location EastUS

Membuat instans Web PubSub

Jalankan az extension add untuk menginstal atau meningkatkan ekstensi webpubsub ke versi saat ini.

az extension add --upgrade --name webpubsub

Gunakan perintah az webpubsub create Azure CLI untuk membuat Web PubSub di grup sumber daya yang telah Anda buat. Perintah berikut membuat sumber daya Web PubSub Gratis di bawah grup sumber daya myResourceGroup di EastUS:

Penting

Setiap sumber daya Web PubSub harus memiliki nama yang unik. Ganti <your-unique-resource-name> dengan nama Web PubSub Anda dalam contoh berikut.

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

Keluaran dari perintah ini menunjukkan properti sumber daya yang baru dibuat. Perhatikan dua properti yang tercantum di bawah:

  • Nama Sumber Daya: Nama yang Anda berikan untuk parameter --name di atas.
  • hostName: Dalam contoh, nama host adalah <your-unique-resource-name>.webpubsub.azure.com/.

Pada titik ini, akun Azure Anda adalah satu-satunya yang berwenang untuk melakukan operasi apa pun di sumber daya baru ini.

Mendapatkan ConnectionString untuk penggunaan di masa mendatang

Penting

String koneksi menyertakan informasi otorisasi yang diperlukan agar aplikasi Anda mengakses layanan Azure Web PubSub. Kunci akses di dalam string koneksi mirip dengan kata sandi root untuk layanan Anda. Di lingkungan produksi, selalu berhati-hatilah untuk melindungi kunci akses Anda. Gunakan Azure Key Vault untuk mengelola dan memutar kunci Anda dengan aman. Hindari mendistribusikan kunci akses ke pengguna lain, melakukan hard-coding, atau menyimpannya di mana saja dalam teks biasa yang dapat diakses orang lain. Putar kunci Anda jika Anda yakin bahwa kunci tersebut mungkin telah disusupi.

Gunakan perintah Azure CLI az webpubsub key untuk mendapatkan ConnectionString layanan. <your-unique-resource-name> Ganti tempat penampung dengan nama instans Azure Web PubSub Anda.

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

Salin string koneksi untuk digunakan nanti.

Salin Koneksi ionString yang diambil dan atur ke dalam variabel WebPubSubConnectionStringlingkungan , yang kemudian dibaca tutorial. Ganti <connection-string> di bawah ini dengan Koneksi ionString yang Anda ambil.

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

Menyiapkan proyek

Prasyarat

Buat aplikasi

Di Azure Web PubSub, ada dua peran, server dan klien. Konsep ini mirip dengan peran server dan klien dalam aplikasi web. Server bertanggung jawab untuk mengelola klien, mendengarkan, dan merespons pesan klien. Klien bertanggung jawab untuk mengirim dan menerima pesan pengguna dari server dan memvisualisasikannya untuk pengguna akhir.

Dalam tutorial ini, kami membangun aplikasi web obrolan real-time. Dalam aplikasi web nyata, tanggung jawab server juga mencakup proses autentikasi klien dan penyajian halaman web statis untuk UI aplikasi.

Kami menggunakan ASP.NET Core 8 untuk menghosting halaman web dan menangani permintaan masuk.

Pertama mari kita buat aplikasi web ASP.NET Core di chatapp folder.

  1. Buat aplikasi web baru.

    mkdir chatapp
    cd chatapp
    dotnet new web
    
  2. Tambahkan app.UseStaticFiles() Program.cs untuk mendukung hosting halaman web statis.

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    
    app.UseStaticFiles();
    
    app.Run();
    
  3. Buat file HTML dan simpan sebagai wwwroot/index.html, kami menggunakannya untuk UI aplikasi obrolan nanti.

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

Anda dapat menguji server dengan menjalankan dotnet run --urls http://localhost:8080 dan mengakses http://localhost:8080/index.html di browser.

Menambahkan titik akhir negosiasi

Dalam tutorial Menerbitkan dan berlangganan pesan, pelanggan mengonsumsi string koneksi secara langsung. Dalam aplikasi dunia nyata, tidak aman untuk berbagi string koneksi dengan klien mana pun, karena string koneksi memiliki hak istimewa tinggi untuk melakukan operasi apa pun ke layanan. Sekarang, mari kita minta server Anda menggunakan string koneksi, dan mengekspos negotiate titik akhir agar klien mendapatkan URL lengkap dengan token akses. Dengan cara seperti itu, server dapat menambahkan middleware autentikasi sebelum negotiate titik akhir untuk mencegah akses yang tidak sah.

Pertama-tama instal dependensi.

dotnet add package Microsoft.Azure.WebPubSub.AspNetCore

Sekarang mari kita tambahkan /negotiate titik akhir untuk panggilan klien untuk menghasilkan token.

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>() digunakan untuk menyuntikkan klien WebPubSubServiceClient<THub>layanan , yang dapat kita gunakan dalam langkah negosiasi untuk menghasilkan token koneksi klien dan dalam metode hub untuk memanggil REST API layanan ketika peristiwa hub dipicu. Kode pembuatan token ini mirip dengan yang kami gunakan dalam tutorial pesan penerbitan dan berlangganan, kecuali kami melewati satu argumen lagi (userId) saat pembuatan token. ID Pengguna dapat digunakan untuk mengidentifikasi identitas klien sehingga ketika Anda menerima pesan, Anda tahu dari mana pesan itu berasal.

Kode membaca string koneksi dari variabel WebPubSubConnectionString lingkungan yang kami tetapkan di langkah sebelumnya.

Jalankan ulang server menggunakan dotnet run --urls http://localhost:8080.

Anda dapat menguji API ini dengan mengakses http://localhost:8080/negotiate?id=user1 dan memberi Anda url lengkap Azure Web PubSub dengan token akses.

Menangani peristiwa

Di Azure Web PubSub, ketika ada aktivitas tertentu terjadi di sisi klien (misalnya klien terhubung, terhubung, terputus, atau klien mengirim pesan), layanan mengirimkan pemberitahuan ke server sehingga dapat bereaksi terhadap peristiwa ini.

Kejadian dikirim ke server dalam bentuk Webhook. Webhook dilayani dan diekspos oleh server aplikasi dan terdaftar di sisi layanan Azure Web PubSub. Layanan ini memanggil webhook setiap kali suatu kejadian terjadi.

Azure Web PubSub mengikuti CloudEvents untuk menggambarkan data kejadian.

Di bawah ini kami menangani connected peristiwa sistem saat klien terhubung dan menangani message peristiwa pengguna saat klien mengirim pesan untuk membangun aplikasi obrolan.

Web PubSub SDK untuk AspNetCore Microsoft.Azure.WebPubSub.AspNetCore yang kami instal pada langkah sebelumnya juga dapat membantu mengurai dan memproses permintaan CloudEvents.

Pertama, tambahkan penanganan aktivitas sebelum app.Run(). Tentukan jalur titik akhir untuk kejadian, katakanlah /eventhandler.

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

Sekarang, di dalam kelas Sample_ChatApp yang kami buat di langkah sebelumnya, tambahkan konstruktor untuk bekerja dengan WebPubSubServiceClient<Sample_ChatApp> yang kami gunakan untuk memanggil layanan Web PubSub. Dan OnConnectedAsync() untuk merespons saat connected peristiwa dipicu, OnMessageReceivedAsync() untuk menangani pesan dari klien.

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

Dalam kode di atas, kami menggunakan klien layanan untuk menyiarkan pesan pemberitahuan dalam format JSON kepada semua yang bergabung dengan SendToAllAsync.

Memperbarui halaman web

Sekarang mari kita perbarui index.html untuk menambahkan logika untuk menyambungkan, mengirim pesan, dan menampilkan pesan yang diterima di halaman.

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

Anda dapat melihat dalam kode di atas yang kami sambungkan menggunakan API WebSocket asli di browser, dan menggunakan WebSocket.send() untuk mengirim pesan dan WebSocket.onmessage mendengarkan pesan yang diterima.

Anda juga dapat menggunakan SDK Klien untuk terhubung ke layanan, yang memberdayakan Anda dengan koneksi ulang otomatis, penanganan kesalahan, dan banyak lagi.

Sekarang ada satu langkah tersisa agar obrolan berfungsi. Mari kita konfigurasi peristiwa apa yang kita pedulikan dan ke mana harus mengirim acara di layanan Web PubSub.

Menyiapkan penanganan aktivitas

Kami mengatur penanganan aktivitas di layanan Web PubSub untuk memberi tahu layanan tempat mengirim peristiwa.

Ketika server web berjalan secara lokal, bagaimana layanan Web PubSub memanggil localhost jika tidak memiliki titik akhir yang dapat diakses internet? Biasanya ada dua cara. Salah satunya adalah mengekspos localhost ke publik menggunakan beberapa alat terowongan umum, dan yang lainnya adalah menggunakan terowongan awps untuk membuat terowongan lalu lintas dari layanan Web PubSub melalui alat ke server lokal Anda.

Di bagian ini, kami menggunakan Azure CLI untuk mengatur penanganan aktivitas dan menggunakan awps-tunnel untuk merutekan lalu lintas ke localhost.

Mengonfigurasi setelan hub

Kami mengatur templat URL untuk menggunakan tunnel skema sehingga Web PubSub merutekan pesan melalui awps-tunnelkoneksi terowongan . Penanganan aktivitas dapat diatur dari portal atau CLI seperti yang dijelaskan dalam artikel ini, di sini kita mengaturnya melalui CLI. Karena kami mendengarkan peristiwa di jalur /eventhandler sebagai set langkah sebelumnya, kami mengatur templat url ke tunnel:///eventhandler.

Gunakan perintah azure CLI az webpubsub hub create untuk membuat pengaturan penanganan aktivitas untuk Sample_ChatApp hub.

Penting

Ganti <your-unique-resource-name> dengan nama sumber daya Web PubSub Anda yang dibuat dari langkah-langkah sebelumnya.

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"

Jalankan awps-tunnel secara lokal

Mengunduh dan menginstal awps-tunnel

Alat ini berjalan pada Node.js versi 16 atau yang lebih tinggi.

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

Gunakan layanan string koneksi dan jalankan

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

Menjalankan server web

Sekarang semuanya sudah diatur. Mari kita jalankan server web dan bermain dengan aplikasi obrolan yang sedang beraksi.

Sekarang jalankan server menggunakan dotnet run --urls http://localhost:8080.

Sampel kode lengkap dari tutorial ini dapat ditemukan di sini.

Buka http://localhost:8080/index.html. Anda dapat memasukkan nama pengguna dan mulai mengobrol.

Lazy Auth dengan connect penanganan aktivitas

Di bagian sebelumnya, kami menunjukkan cara menggunakan titik akhir negosiasi untuk mengembalikan URL layanan Web PubSub dan token akses JWT bagi klien untuk terhubung ke layanan Web PubSub. Dalam beberapa kasus, misalnya, perangkat edge yang memiliki sumber daya terbatas, klien mungkin lebih suka terhubung langsung ke sumber daya Web PubSub. Dalam kasus seperti itu, Anda dapat mengonfigurasi connect penanganan aktivitas untuk malas auth klien, menetapkan ID pengguna ke klien, menentukan grup yang bergabung dengan klien setelah mereka terhubung, mengonfigurasi izin yang dimiliki klien dan subprotokol WebSocket sebagai respons WebSocket ke klien, dll. Detail silakan lihat menghubungkan spesifikasi penanganan aktivitas.

Sekarang mari kita gunakan connect penanganan aktivitas untuk mencapai hal serupa seperti yang dilakukan bagian negosiasi .

Memperbarui pengaturan hub

Pertama mari kita perbarui pengaturan hub untuk juga menyertakan connect penanganan aktivitas, kita juga perlu mengizinkan koneksi anonim sehingga klien tanpa token akses JWT dapat terhubung ke layanan.

Gunakan perintah pembaruan hub azure CLI az webpubsub untuk membuat pengaturan penanganan aktivitas untuk Sample_ChatApp hub.

Penting

Ganti <your-unique-resource-name> dengan nama sumber daya Web PubSub Anda yang dibuat dari langkah-langkah sebelumnya.

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"

Memperbarui logika upstream untuk menangani peristiwa sambungkan

Sekarang mari kita perbarui logika upstream untuk menangani peristiwa sambungkan. Kita juga bisa menghapus titik akhir negosiasi sekarang.

Seperti halnya apa yang kami lakukan dalam menegosiasikan titik akhir sebagai tujuan demo, kami juga membaca id dari parameter kueri. Dalam peristiwa sambungkan, kueri klien asli dipertahankan dalam isi kueri ulang peristiwa sambungkan.

Di dalam kelas Sample_ChatApp, ambil alih OnConnectAsync() untuk menangani connect peristiwa:

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

Memperbarui index.html untuk menyambungkan langsung

Sekarang mari kita perbarui halaman web untuk mengarahkan koneksi ke layanan Web PubSub. Satu hal yang perlu disebutkan adalah bahwa sekarang untuk tujuan demo titik akhir layanan Web PubSub dikodekan secara permanen ke dalam kode klien, harap perbarui nama <the host name of your service> host layanan di html di bawah ini dengan nilai dari layanan Anda sendiri. Mungkin masih berguna untuk mengambil nilai titik akhir layanan Web PubSub dari server Anda, ini memberi Anda lebih banyak fleksibilitas dan kontrolbilitas ke tempat klien terhubung.

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

Jalankan ulang server

Sekarang jalankan ulang server dan kunjungi halaman web dengan mengikuti instruksi sebelumnya. Jika Anda telah berhenti awps-tunnel, silakan jalankan kembali alat terowongan.

Langkah berikutnya

Tutorial ini memberi Anda gambaran dasar tentang cara kerja sistem peristiwa di layanan Azure Web PubSub.

Lihat tutorial lain untuk mempelajari lebih lanjut cara menggunakan layanan ini.