SignalR .NET-Client, der in einer Blazor .NET Core 3-Anwendung eine Verbindung zum Azure SignalR-Dienst herstellt


11

Ich versuche, eine Verbindung zwischen meiner ASP.NET Core 3.0 Blazor-Anwendung (serverseitig) und dem Azure SignalR-Dienst herzustellen. Am Ende injiziere ich meinen SignalR-Client (Service) in einige Blazor-Komponenten, damit diese meine Benutzeroberfläche / mein DOM in Echtzeit aktualisieren.

Mein Problem ist, dass ich die folgende Nachricht erhalte, wenn ich meine .StartAsync()Methode über die Hub-Verbindung aufrufe:

Der Antwortstatuscode zeigt keinen Erfolg an: 404 (Nicht gefunden).

BootstrapSignalRClient.cs

Diese Datei lädt meine Konfiguration für den SignalR-Dienst, einschließlich URL, Verbindungszeichenfolge, Schlüssel, Methodenname und Hubname. Diese Einstellungen werden in der statischen Klasse erfasst SignalRServiceConfigurationund später verwendet.

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

Ich habe Erfahrung mit der Verwendung von SignalR mit .NET Core, wo Sie es hinzufügen, sodass für die Startup.csDatei, die .AddSignalR().AddAzureSignalR()einen Hub in der App-Konfiguration verwendet und zuordnet , bestimmte Konfigurationsparameter eingerichtet werden müssen (z. B. Verbindungszeichenfolge).

Woher kommt in meiner Situation HubConnectionBuilderdie Verbindungszeichenfolge oder ein Schlüssel zur Authentifizierung beim SignalR-Dienst?

Ist es möglich, dass die Nachricht 404 ein Ergebnis des fehlenden Schlüssels / der fehlenden Verbindungszeichenfolge ist?


1
.WithUrl(signalRConfig.Url + signalRConfig.HubName)Können Sie überprüfen, ob dies zur richtigen URL führt? (Durch Haltepunkt oder Protokollierung?)
— Fildor

Ich fand es nützlich, die Basis Uri als zu haben Uriund die vollständige über Uri (Uri, String) zu
— konstruieren

Interessanterweise war es ein "roter Hering" und hatte nichts mit dem 404 zu tun.
— Jason Shave

Antworten:


8

Okay, es stellt sich heraus, dass der Dokumentation hier eine wichtige Information fehlt. Wenn Sie den .NET SignalR-Client verwenden, der eine Verbindung zum Azure SignalR-Dienst herstellt, müssen Sie ein JWT-Token anfordern und beim Erstellen der Hub-Verbindung vorlegen.

Wenn Sie sich im Namen eines Benutzers authentifizieren müssen, können Sie dieses Beispiel verwenden.

Andernfalls können Sie einen "/ Verhandlungs" -Endpunkt mithilfe einer Web-API wie einer Azure-Funktion einrichten, um ein JWT-Token und eine Client-URL für Sie abzurufen. Das habe ich letztendlich für meinen Anwendungsfall getan. Informationen zum Erstellen einer Azure-Funktion zum Abrufen Ihres JWT-Tokens und Ihrer URL finden Sie hier.

Ich habe eine Klasse erstellt, die diese beiden Werte als solche enthält:

SignalRConnectionInfo.cs

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

Ich habe auch eine Methode in meinem erstellt SignalRService, um die Interaktion mit dem Endpunkt "/ Verhandlung" der Web-API in Azure, die Instanziierung der Hub-Verbindung und die Verwendung eines Ereignisses + Delegaten zum Empfangen von Nachrichten wie folgt zu handhaben:

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

Dies functionsClientist einfach eine stark typisierte HttpClientVorkonfiguration mit einer Basis-URL und FunctionsClientConstants.SignalReine statische Klasse mit dem Pfad "/ Verhandeln", der an die Basis-URL angehängt wird.

Nachdem ich alles eingerichtet hatte, rief ich das an await hubConnection.StartAsync();und es "verbunden"!

Nach all dem habe ich ein statisches ReceiveMessageEreignis und einen Delegaten wie folgt eingerichtet (im selben SignalRClient.cs):

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

Zuletzt habe ich den ReceiveMessageDelegierten implementiert :

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

Ich habe dem Azure SignalR Service-Team Dokumentationsaktualisierungen zur Verfügung gestellt und hoffe, dass dies jemand anderem hilft!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.