【问题标题】:SignalR .NET Client connecting to Azure SignalR Service in a Blazor .NET Core 3 applicationSignalR .NET 客户端连接到 Blazor .NET Core 3 应用程序中的 Azure SignalR 服务
【发布时间】:2019-10-05 21:00:31
【问题描述】:

我正在尝试在我的 ASP.NET Core 3.0 Blazor(服务器端)应用程序和 Azure SignalR 服务之间建立连接。我最终会将我的 SignalR 客户端(服务)注入到一些 Blazor 组件中,以便它们实时更新我的​​ UI/DOM。

我的问题是,当我在集线器连接上调用 .StartAsync() 方法时收到以下消息:

响应状态码不表示成功:404(未找到)。

BootstrapSignalRClient.cs

此文件加载我的 SignalR 服务配置,包括 URL、连接字符串、密钥、方法名称和集线器名称。这些设置在静态类SignalRServiceConfiguration 中被捕获并在以后使用。

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

我有使用 SignalR 和 .NET Core 的经验,您可以在其中添加它,以便使用 .AddSignalR().AddAzureSignalR()Startup.cs 文件并在应用程序配置中映射一个集线器,并且这样做需要建立某些“配置”参数(即连接字符串)。

鉴于我的情况,HubConnectionBuilder 从哪里获取连接字符串或密钥以对 SignalR 服务进行身份验证?

404 消息是否可能是缺少密钥/连接字符串的结果?

【问题讨论】:

  • .WithUrl(signalRConfig.Url + signalRConfig.HubName) 你能确认这导致了正确的 URL 吗? (通过断点还是日志记录?)
  • 我发现将基本 Uri 设置为 Uri 并通过 Uri(Uri, string) 构建完整的 Uri 很有用
  • 有趣的是,这是一条“红鲱鱼”,与 404 无关。

标签: c# signalr signalr.client asp.net-core-signalr azure-signalr


【解决方案1】:

好的,事实证明文档在这里缺少关键信息。如果您使用 .NET SignalR 客户端连接到 Azure SignalR 服务,则需要请求 JWT 令牌并在创建集线器连接时提供它。

如果您需要代表用户进行身份验证,您可以使用this example.

否则,您可以使用 Azure 函数等 Web API 设置“/negotiate”端点,为您检索 JWT 令牌和客户端 URL;这就是我最终为我的用例所做的。可以找到有关创建 Azure 函数以获取 JWT 令牌和 URL 的信息here.

我创建了一个类来保存这两个值:

SignalRConnectionInfo.cs

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

我还在我的SignalRService 中创建了一个方法来处理与 Azure 中 Web API 的“/negotiate”端点的交互、集线器连接的实例化以及使用事件 + 委托来接收消息,如下所示:

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

functionsClient 是一个简单的强类型 HttpClient,预先配置了一个基本 URL,FunctionsClientConstants.SignalR 是一个静态类,带有附加到基本 URL 的“/negotiate”路径。

完成所有设置后,我打电话给await hubConnection.StartAsync();,它“已连接”!

毕竟我设置了一个静态ReceiveMessage事件和一个委托如下(在同一个SignalRClient.cs中):

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

最后,我实现了ReceiveMessage委托:

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

我已将文档更新提供给 Azure SignalR 服务团队,当然希望这对其他人有所帮助!

【讨论】:

    【解决方案2】:

    更新:带有用于管理 SDK (sample) 的无服务器示例 is deprecated 的示例。管理 SDK 使用协商服务器。

    【讨论】:

    • 这应该是评论而不是答案
    • 我知道,但我无法将其添加为评论 - 缺少所需的点 :(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-24
    • 2020-06-30
    • 1970-01-01
    • 2019-10-07
    相关资源
    最近更新 更多