Klient SignalR .NET łączy się z usługą Azure SignalR w aplikacji Blazor .NET Core 3


11

Próbuję nawiązać połączenie między moją aplikacją ASP.NET Core 3.0 Blazor (po stronie serwera) a usługą Azure SignalR. W końcu wprowadzę mojego klienta SignalR (usługę) do kilku komponentów Blazora, aby zaktualizowali mój interfejs użytkownika / DOM w czasie rzeczywistym.

Mój problem polega na tym, że podczas wywoływania .StartAsync()metody w połączeniu z koncentratorem pojawia się następujący komunikat :

Kod statusu odpowiedzi nie oznacza sukcesu: 404 (Nie znaleziono).

BootstrapSignalRClient.cs

Ten plik ładuje moją konfigurację usługi SignalR, w tym adres URL, parametry połączenia, klucz, nazwę metody i nazwę koncentratora. Te ustawienia są przechwytywane w klasie statycznej SignalRServiceConfigurationi używane później.

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

Mam doświadczenie w korzystaniu z SignalR z .NET Core, gdzie dodajesz go, więc Startup.csplik używający .AddSignalR().AddAzureSignalR()i mapujący koncentrator w konfiguracji aplikacji i zrobienie tego w ten sposób wymaga ustalenia pewnych parametrów „konfiguracji” (tj. Ciągu połączenia).

Biorąc pod uwagę moją sytuację, skąd HubConnectionBuilderbierze się ciąg połączenia lub klucz do uwierzytelnienia w usłudze SignalR?

Czy to możliwe, że komunikat 404 jest wynikiem brakującego klucza / ciągu połączenia?


1
.WithUrl(signalRConfig.Url + signalRConfig.HubName)Czy możesz sprawdzić, czy to prowadzi do poprawnego adresu URL? (Przez punkt przerwania lub logowanie?)
— Fildor,

Uznałem, że użyteczne jest posiadanie podstawowego Uri as Urii zbudowanie kompletnego za pomocą Uri (Uri, string)
— Fildor,

co ciekawe, był to „czerwony śledź” i nie miał nic wspólnego z 404.
— Jason Shave,

Odpowiedzi:


8

Okej, więc okazuje się, że w dokumentacji brakuje tutaj kluczowych informacji. Jeśli używasz klienta .NET SignalR Client łączącego się z usługą Azure SignalR, musisz poprosić o token JWT i przedstawić go podczas tworzenia połączenia koncentratora.

Jeśli potrzebujesz uwierzytelnić w imieniu użytkownika, możesz skorzystać z tego przykładu.

W przeciwnym razie można skonfigurować punkt końcowy „/ negocjować” za pomocą internetowego interfejsu API, takiego jak funkcja Azure, aby pobrać za Ciebie token JWT i adres URL klienta; to właśnie skończyło się na moim przypadku użycia. Informacje na temat tworzenia funkcji platformy Azure w celu uzyskania tokena JWT i adresu URL można znaleźć tutaj.

Utworzyłem klasę do przechowywania tych dwóch wartości jako takich:

SignalRConnectionInfo.cs

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

Utworzyłem również metodę SignalRServiceobsługi interakcji z punktem końcowym interfejsu API sieci Web „/ negocjuj” na platformie Azure, tworzenia instancji połączenia z koncentratorem oraz użycia zdarzenia + delegata do otrzymywania wiadomości w następujący sposób:

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

Jest functionsClientto po prostu mocno wpisany, HttpClientwstępnie skonfigurowany podstawowy adres URL, a FunctionsClientConstants.SignalRjest to klasa statyczna ze ścieżką „/ negocjuj”, która jest dołączana do podstawowego adresu URL.

Kiedy już to wszystko skonfigurowałem, zadzwoniłem do await hubConnection.StartAsync();i „połączono”!

Po tym wszystkim skonfigurowałem ReceiveMessagezdarzenie statyczne i delegata w następujący sposób (w tym samym SignalRClient.cs):

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

Na koniec zaimplementowałem ReceiveMessagedelegata:

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

Dostarczyłem aktualizacje dokumentacji z powrotem do zespołu usługi Azure SignalR Service i mam nadzieję, że pomoże to komuś innemu!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.