Client SignalR .NET che si connette al servizio SignalR di Azure in un'applicazione Blazor .NET Core 3


11

Sto cercando di stabilire una connessione tra la mia applicazione ASP.NET Core 3.0 Blazor (lato server) e il servizio Azure SignalR. Finirò per iniettare il mio client SignalR (servizio) in alcuni componenti Blazor in modo che aggiorneranno la mia UI / DOM in tempo reale.

Il mio problema è che ricevo il seguente messaggio quando chiamo il mio .StartAsync()metodo sulla connessione hub:

Il codice dello stato della risposta non indica l'esito positivo: 404 (non trovato).

BootstrapSignalRClient.cs

Questo file carica la mia configurazione per il servizio SignalR incluso l'URL, la stringa di connessione, la chiave, il nome del metodo e il nome dell'hub. Queste impostazioni vengono acquisite nella classe statica SignalRServiceConfiguratione utilizzate in seguito.

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

Ho esperienza nell'uso di SignalR con .NET Core in cui lo aggiungi, quindi il Startup.csfile che usa .AddSignalR().AddAzureSignalR()e mappa un hub nella configurazione dell'app e farlo in questo modo richiede che vengano stabiliti alcuni parametri di "configurazione" (cioè stringa di connessione).

Data la mia situazione, da dove HubConnectionBuilderviene la stringa di connessione o una chiave per l'autenticazione al servizio SignalR?

È possibile che il messaggio 404 sia il risultato della chiave mancante / stringa di connessione?


1
.WithUrl(signalRConfig.Url + signalRConfig.HubName)Puoi verificare che ciò stia generando l'URL corretto? (Per breakpoint o registrazione?)
Fildor

Ho trovato utile avere la base Uri come Urie costruire quella completa via Uri (Uri, stringa)
Fildor

è interessante notare che si trattava di un'aringa rossa e non aveva nulla a che fare con il 404.
Jason Shave,

Risposte:


8

Va bene, quindi risulta che la documentazione non contiene informazioni chiave qui. Se si utilizza .NET SignalR Client per la connessione al servizio SignalR di Azure, è necessario richiedere un token JWT e presentarlo durante la creazione della connessione hub.

Se è necessario autenticarsi per conto di un utente, è possibile utilizzare questo esempio.

Altrimenti, è possibile impostare un endpoint "/ negoziazione" usando un'API Web come una funzione di Azure per recuperare un token JWT e un URL client; questo è quello che ho finito per fare per il mio caso d'uso. Le informazioni sulla creazione di una funzione di Azure per ottenere il token e l'URL JWT sono disponibili qui.

Ho creato una classe per contenere questi due valori come tali:

SignalRConnectionInfo.cs

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

Ho anche creato un metodo all'interno di my SignalRServiceper gestire l'interazione con l'endpoint "/ negozia" dell'API Web in Azure, l'istanza della connessione hub e l'uso di un evento + delegato per ricevere messaggi come segue:

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

Il functionsClientè semplicemente un tipizzata HttpClientpre-configurato con un URL di base e la FunctionsClientConstants.SignalRè una classe statica con la "/ negoziare" percorso è allegato alla URL di base.

Una volta che ho fatto tutto questo ho chiamato il await hubConnection.StartAsync();"e collegato"!

Dopo tutto ciò ho impostato un ReceiveMessageevento statico e un delegato come segue (nello stesso SignalRClient.cs):

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

Infine, ho implementato il ReceiveMessagedelegato:

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

Ho fornito aggiornamenti della documentazione al team del servizio SignalR di Azure e spero che questo aiuti qualcun altro!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.