使用 Azure SignalR 管理 SDK

Azure SignalR 管理 SDK 可帮助你直接通过 Azure SignalR 服务管理 SignalR 客户端,例如广播消息。 因此,该 SDK 可以但不限于在无服务器环境中使用。 可以使用此 SDK 在任何环境(例如在控制台应用程序、Azure 函数或 Web 服务器)中管理连接到 Azure SignalR 服务的 SignalR 客户端。

注意

若要查看 SDK 版本 1.9.x 及更早版本的指南,请转到 Azure SignalR 服务管理 SDK(旧版)。 你可能还需要阅读迁移指南

功能

功能 暂时 永久
广播
广播(某些客户端除外)
发送到客户端
发送到客户端
发送给用户
发送给用户
发送给组
发送到组
发送到组(某些客户端除外)
将用户添加到组
从组中移除用户
检查某个用户是否在组中
支持多个 SignalR 服务实例
MessagePack 客户端支持 自 v1.21.0 起 自 v1.20.0 起
重试暂时性错误 自 v1.22.0 起

功能仅随新的 API 提供

功能 暂时 永久
检查连接是否存在 自 v1.11 起
检查组是否存在 自 v1.11 起
检查用户是否存在 自 v1.11 起
关闭客户端连接 自 v1.11 起
  • 此处可以找到关于不同模式的更多详细信息。

  • 此处可以找到有关管理 SDK 的完整示例。

使用情况

本部分介绍如何使用管理 SDK。

创建 Service Manager

ServiceManagerBuilder 生成 ServiceManager 实例


var serviceManager = new ServiceManagerBuilder()
                    .WithOptions(option =>
                    {
                        option.ConnectionString = "<Your Azure SignalR Service Connection String>";
                    })
                    .WithLoggerFactory(loggerFactory)
                    .BuildServiceManager();

可以使用 ServiceManager 来检查 Azure SignalR 终结点运行状况并创建服务中心上下文。 以下部分提供了有关创建服务中心上下文的详细信息。

若要检查 Azure SignalR 终结点运行状况,可以使用 ServiceManager.IsServiceHealthy 方法。 如果有多个 Azure SignalR 终结点,则只会检查第一个终结点。

var health = await serviceManager.IsServiceHealthy(cancellationToken);

创建服务中心上下文

ServiceManager 创建 ServiceHubContext 实例:

var serviceHubContext = await serviceManager.CreateHubContextAsync("<Your Hub Name>",cancellationToken);

协商

默认模式下,Azure SignalR 服务 SDK 会公开终结点 /<Your Hub Name>/negotiate 以进行协商。 SignalR 客户端会访问此终结点,然后重定向到 Azure SignalR 服务。

无服务器模式下,我们建议托管协商终结点来为 SignalR 客户端的协商请求提供服务,并将客户端重定向到 Azure SignalR 服务。

提示

阅读有关 SignalR 协商协议重定向的更多详细信息。

若要将 SignalR 客户端重定向到 Azure SignalR 服务,端点和访问令牌都很有用。

可以使用 ServiceHubContext 实例为 SignalR 客户端生成终结点 URL 和相应的访问令牌,从而连接到 Azure SignalR 服务。

var negotiationResponse = await serviceHubContext.NegotiateAsync(new (){UserId = "<Your User Id>"});

假设中心终结点为 http://<Your Host Name>/<Your Hub Name>,那么协商终结点为 http://<Your Host Name>/<Your Hub Name>/negotiate。 托管协商终结点后,可以使用 SignalR 客户端连接到中心,如下所示:

var connection = new HubConnectionBuilder().WithUrl("http://<Your Host Name>/<Your Hub Name>").Build();
await connection.StartAsync();

有关如何使用管理 SDK 将 SignalR 客户端重定向到 Azure SignalR 服务的示例,请参阅此处

发送消息和管理组

我们从 ServiceHubContextBuilder 生成的 ServiceHubContext 是实施和扩展 IServiceHubContext 的类。 可以使用它将消息发送到客户端和管理组。

try
{
    // Broadcast
    await hubContext.Clients.All.SendAsync(callbackName, obj1, obj2, ...);

    // Send to user
    await hubContext.Clients.User(userId).SendAsync(callbackName, obj1, obj2, ...);

    // Send to group
    await hubContext.Clients.Group(groupId).SendAsync(callbackName, obj1, obj2, ...);

    // add user to group
    await hubContext.UserGroups.AddToGroupAsync(userId, groupName);

    // remove user from group
    await hubContext.UserGroups.RemoveFromGroupAsync(userId, groupName);
}
finally
{
    await hubContext.DisposeAsync();
}

强类型中心

强类型中心是一种编程模型,可以将客户端方法提取到接口中,从而避免拼写错误的方法名称或传递错误的参数类型等错误。

假设我们有一个名为 ReceivedMessage 的客户端方法,其中包含两个字符串参数。 如果没有强类型中心,可以通过 hubContext.Clients.All.SendAsync("ReceivedMessage", user, message) 广播到客户端。 使用强类型中心,首先定义如下所示的接口:

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

然后,创建一个实施 IHubContext<Hub<T>, T> 的强类型中心上下文,其中,T 是客户端方法接口:

ServiceHubContext<IChatClient> serviceHubContext = await serviceManager.CreateHubContextAsync<IChatClient>(hubName, cancellationToken);

最后,可以直接调用该方法:

await Clients.All.ReceiveMessage(user, message);

除了在发送消息方面存在差异,你可以像使用 ServiceHubContext 一样与 ServiceHubContext<T> 协商或管理组。

此处的 ASP.NET Core 文档中了解有关强类型中心的更多信息。

传输类型

此 SDK 可以使用两种传输类型与 Azure SignalR 服务通信:

  • 暂时:为发送的每条消息创建 Http 请求 Azure SignalR 服务。 SDK 只需在暂时模式下封装 Azure SignalR 服务 REST API。 此类型在无法建立 WebSocket 连接时非常有用。
  • 永久:首先创建 WebSocket 连接,然后发送此连接中的所有消息。 此类型在发送大量消息时非常有用。

消息中自变量的序列化行为摘要

序列化 暂时 永久
默认 JSON 库 Newtonsoft.Json 与 ASP.NET Core SignalR 相同:
Newtonsoft.Json 适用于 .NET Standard 2.0;
System.Text.Json 适用于 .NET Core App 3.1 及更高版本
MessagePack 客户端支持 自 v1.21.0 起 自 v1.20.0 起

JSON 序列化

在管理 SDK 中,发送到客户端的方法参数被序列化为 JSON。 可以通过多种方式自定义 JSON 序列化。 我们按照从最推荐到最不推荐的顺序显示所有方法。

ServiceManagerOptions.UseJsonObjectSerializer(ObjectSerializer objectSerializer)

最推荐的方法是使用通用抽象类 ObjectSerializer,因为它支持不同的 JSON 序列化库,例如 System.Text.JsonNewtonsoft.Json,并且适用于所有传输类型。 通常,你不需要自己实施 ObjectSerializer,因为已经提供了 System.Text.JsonNewtonsoft.Json 的便捷 JSON 实施。

  • 使用 System.Text.Json 作为 JSON 处理库时,内置 JsonObjectSerializer 将使用 System.Text.Json.JsonSerializer 进行序列化/反序列化。 以下是使用驼峰式大小写命名法进行 JSON 序列化的示例:

    var serviceManager = new ServiceManagerBuilder()
        .WithOptions(o =>
        {
            o.ConnectionString = "***";
            o.UseJsonObjectSerializer(new JsonObjectSerializer(new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            }));
        })
        .BuildServiceManager();
    
    
  • 使用 Newtonsoft.Json 作为 JSON 处理库时,首先使用 .NET CLI 从 NuGet 安装软件包 Microsoft.Azure.Core.NewtonsoftJson

    dotnet add package Microsoft.Azure.Core.NewtonsoftJson
    

    以下是对 NewtonsoftJsonObjectSerializer 使用驼峰式大小写命名的示例:

    var serviceManager = new ServiceManagerBuilder()
        .WithOptions(o =>
        {
            o.ConnectionString = "***";
            o.UseJsonObjectSerializer(new NewtonsoftJsonObjectSerializer(new JsonSerializerSettings()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            }));
        })
        .BuildServiceManager();
    
  • 使用其他 JSON 处理库时

    你也可以自行实施 ObjectSerializer。 以下链接可能有所帮助:

ServiceManagerBuilder.WithNewtonsoftJson(Action<NewtonsoftServiceHubProtocolOptions> configure)

此方法仅适用于 Newtonsoft.Json 用户。 以下是使用驼峰式大小写命名的示例:

var serviceManager = new ServiceManagerBuilder()
    .WithNewtonsoftJson(o =>
    {
        o.PayloadSerializerSettings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
    })
    .BuildServiceManager();
ServiceManagerOptions.JsonSerializerSettings(已弃用)

此方法仅适用于暂时性传输类型。 不使用此选项。

var serviceManager = new ServiceManagerBuilder()
    .WithOptions(o =>
    {
        o.JsonSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    })
    .BuildServiceManager();

消息包序列化

  1. 需要安装 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 包。

  2. 若要使用默认 JSON 协议并行添加 MessagePack 协议,请执行以下操作:

    var serviceManagerBuilder = new ServiceManagerBuilder()
        .AddHubProtocol(new MessagePackHubProtocol());
    
  3. 若要完全控制中心协议,可以使用

        var serviceManagerBuilder = new ServiceManagerBuilder()
            .WithHubProtocols(new MessagePackHubProtocol(), new JsonHubProtocol());
    

    WithHubProtocols 首先清除现有协议,然后添加新协议。 还可以使用此方法移除 JSON 协议,并仅使用 MessagePack。

对于暂时模式,默认情况下,服务端会将 JSON 负载转换为 MessagePack 负载,这是支持 MessagePack 的传统方式。 但是,建议显式添加 MessagePack 中心协议,因为传统方式可能无法按预期工作。

HTTP 请求重试

对于暂时模式,此 SDK 提供在发生暂时性错误时自动重新发送请求的功能,前提是请求是幂等的。 若要启用此功能,可以使用 ServiceManagerOptions.RetryOptions 属性。

具体而言,将重试以下类型的请求:

  • 对于向 SignalR 客户端发送消息的消息请求,如果 HTTP 响应状态代码大于 500,则 SDK 会重试该请求。 当 HTTP 响应代码等于 500 时,可能表示服务端超时,重试请求可能会导致重复消息。

  • 对于其他类型的请求(例如向组添加连接),SDK 会在以下条件下重试请求:

    1. HTTP 响应状态代码在 5xx 范围内,或者请求超时,状态代码为 408(请求超时)。
    2. 请求超时,持续时间长于在 ServiceManagerOptions.HttpClientTimeout 中配置的超时长度。

SDK 只能重试幂等请求,即重复请求不会产生任何其他影响的请求。 如果请求不是幂等的,则可能需要手动处理重试。

后续步骤

本文介绍如何在应用程序中使用 SignalR 服务。 查看以下文章以了解有关 SignalR 服务的更多信息。