SignalR .NET Client yang terhubung ke Azure SignalR Service dalam aplikasi Blazor .NET Core 3

11

Saya mencoba membuat koneksi antara aplikasi ASP.NET Core 3.0 Blazor (sisi server) saya dan Layanan Azure SignalR. Saya akhirnya akan menyuntikkan klien SignalR saya (layanan) ke beberapa komponen Blazor sehingga mereka akan memperbarui UI / DOM saya secara waktu nyata.

Masalah saya adalah saya menerima pesan berikut ketika saya memanggil .StartAsync()metode saya pada koneksi hub:

Kode status respons tidak menunjukkan keberhasilan: 404 (Tidak Ditemukan).

BootstrapSignalRClient.cs

File ini memuat konfigurasi saya untuk Layanan SignalR termasuk URL, string koneksi, kunci, nama metode, dan nama hub. Pengaturan ini ditangkap di kelas statis SignalRServiceConfigurationdan digunakan nanti.

public static class BootstrapSignalRClient
{
    public static IServiceCollection AddSignalRServiceClient(this IServiceCollection services, IConfiguration configuration)
    {
        SignalRServiceConfiguration signalRServiceConfiguration = new SignalRServiceConfiguration();
        configuration.Bind(nameof(SignalRServiceConfiguration), signalRServiceConfiguration);

        services.AddSingleton(signalRServiceConfiguration);
        services.AddSingleton<ISignalRClient, SignalRClient>();

        return services;
    }
}

SignalRServiceConfiguration.cs

public class SignalRServiceConfiguration
{
    public string ConnectionString { get; set; }
    public string Url { get; set; }
    public string MethodName { get; set; }
    public string Key { get; set; }
    public string HubName { get; set; }
}

SignalRClient.cs

public class SignalRClient : ISignalRClient
{
    public delegate void ReceiveMessage(string message);
    public event ReceiveMessage ReceiveMessageEvent;

    private HubConnection hubConnection;

    public SignalRClient(SignalRServiceConfiguration signalRConfig)
    {
        hubConnection = new HubConnectionBuilder()
            .WithUrl(signalRConfig.Url + signalRConfig.HubName)
            .Build();            
    }

    public async Task<string> StartListening(string id)
    {
        // Register listener for a specific id
        hubConnection.On<string>(id, (message) => 
        {
            if (ReceiveMessageEvent != null)
            {
                ReceiveMessageEvent.Invoke(message);
            }
        });

        try
        {
            // Start the SignalR Service connection
            await hubConnection.StartAsync(); //<---I get an exception here
            return hubConnection.State.ToString();
        }
        catch (Exception ex)
        {
            return ex.Message;
        }            
    }

    private void ReceiveMessage(string message)
    {
        response = JsonConvert.DeserializeObject<dynamic>(message);
    }
}

Saya memiliki pengalaman menggunakan SignalR dengan .NET Core di mana Anda menambahkannya sehingga Startup.csfile menggunakan .AddSignalR().AddAzureSignalR()dan memetakan hub di konfigurasi aplikasi dan melakukannya dengan cara ini memerlukan parameter 'konfigurasi' tertentu untuk dibuat (yaitu string koneksi).

Mengingat situasi saya, di mana HubConnectionBuildermendapatkan string koneksi atau kunci untuk mengotentikasi ke Layanan SignalR?

Mungkinkah pesan 404 adalah hasil dari kunci yang hilang / string koneksi?

Jason Shave
sumber
1
.WithUrl(signalRConfig.Url + signalRConfig.HubName)Bisakah Anda memverifikasi ini menghasilkan Url yang benar? (Dengan breakpoint atau logging?)
Fildor
Saya merasa berguna untuk memiliki basis Uri sebagai Uridan membangun yang lengkap melalui Uri (Uri, string)
Fildor
Menariknya itu adalah 'herring merah' dan tidak ada hubungannya dengan 404.
Jason Shave

Jawaban:

8

Oke jadi ternyata dokumentasi kurang informasi kunci di sini. Jika Anda menggunakan .NET SignalR Client yang tersambung ke Layanan Azure SignalR, Anda perlu meminta token JWT dan menyajikannya saat membuat koneksi hub.

Jika Anda perlu mengautentikasi atas nama pengguna, Anda dapat menggunakan contoh ini.

Jika tidak, Anda dapat menyiapkan titik akhir "/ negosiasi" menggunakan API web seperti Fungsi Azure untuk mengambil kembali token JWT dan URL klien untuk Anda; inilah yang akhirnya saya lakukan untuk kasus penggunaan saya. Informasi tentang membuat Fungsi Azure untuk mendapatkan token JWT Anda dan URL dapat ditemukan di sini.

Saya membuat kelas untuk menampung dua nilai ini seperti:

SignalRConnectionInfo.cs

public class SignalRConnectionInfo
{
    [JsonProperty(PropertyName = "url")]
    public string Url { get; set; }
    [JsonProperty(PropertyName = "accessToken")]
    public string AccessToken { get; set; }
}

Saya juga membuat metode di dalam saya SignalRServiceuntuk menangani interaksi dengan titik akhir "/ negosiasikan" API web di Azure, instantiation koneksi hub, dan penggunaan delegasi event + untuk menerima pesan sebagai berikut:

SignalRClient.cs

public async Task InitializeAsync()
{
    SignalRConnectionInfo signalRConnectionInfo;
    signalRConnectionInfo = await functionsClient.GetDataAsync<SignalRConnectionInfo>(FunctionsClientConstants.SignalR);

    hubConnection = new HubConnectionBuilder()
        .WithUrl(signalRConnectionInfo.Url, options =>
        {
           options.AccessTokenProvider = () => Task.FromResult(signalRConnectionInfo.AccessToken);
        })
        .Build();
}

Ini functionsClienthanyalah tipe HttpClientpra-konfigurasi yang diketik dengan kuat dengan basis URL dan FunctionsClientConstants.SignalRmerupakan kelas statis dengan jalur "/ negotiate" yang ditambahkan ke URL dasar.

Setelah saya mengatur semua ini, saya menelepon await hubConnection.StartAsync();dan "terhubung"!

Setelah semua ini, saya membuat ReceiveMessageacara statis dan delegasi sebagai berikut (dalam yang sama SignalRClient.cs):

public delegate void ReceiveMessage(string message);
public static event ReceiveMessage ReceiveMessageEvent;

Terakhir, saya menerapkan ReceiveMessagedelegasi:

await signalRClient.InitializeAsync(); //<---called from another method

private async Task StartReceiving()
{
    SignalRStatus = await signalRClient.ReceiveReservationResponse(Response.ReservationId);
    logger.LogInformation($"SignalR Status is: {SignalRStatus}");

    // Register event handler for static delegate
    SignalRClient.ReceiveMessageEvent += signalRClient_receiveMessageEvent;
}

private async void signalRClient_receiveMessageEvent(string response)
{
    logger.LogInformation($"Received SignalR mesage: {response}");
    signalRReservationResponse = JsonConvert.DeserializeObject<SignalRReservationResponse>(response);
    await InvokeAsync(StateHasChanged); //<---used by Blazor (server-side)
}

Saya telah memberikan pembaruan dokumentasi kembali ke tim Layanan Azure SignalR dan yakin ini membantu orang lain!

Jason Shave
sumber