Azure 服务总线与 SignalR 集成

Azure Service Bus integration with SignalR

此问题与使用 SignalR 和 Azure 服务总线进行横向扩展无关。我想在我的 SignalR 网络套接字应用程序中构建一个服务总线侦听器(例如 OnMessage),然后将消息相应地分发给连接的用户。消息将从各种单独的 运行 服务发布到集中式服务总线,连接到 Web 套接字服务器的 UI/browser 应该接收这些消息。

选项 1:我可以将异步任务添加到集线器方法中以订阅服务总线并按连接的用户进行过滤。这样做的问题是它使用线程池中的一个额外线程,并将对用户启动的 每个 套接字连接执行此操作。我们的应用程序可以为每个打开的选项卡轻松启动 5-10 个或更多套接字。

选项 2:我可以将单个任务添加到 SignalR Startup.Configuration 方法,然后接收所有消息并将它们分发给正确的连接用户。我在这里遇到的问题是我无法访问用于发送到浏览器的客户端对象。

我觉得 SignalR 和 Service Bus 可以很好地互补以实现近乎实时的通信,但我发现很少有东西可以实现这样的场景。我觉得这应该是一个足够普遍的场景。也许我遗漏了一些明显的设计模式,这将是一个更好的解决方案。

我想通了。在 SignalR Startup.Configuration 方法中,我添加了一个方法来启动侦听器,并在该方法中调用了 GlobalHost.ConnectionManager.GetHubContext。目前这不会发送给个人用户,但我会添加某种连接管理器来处理它。

public void startServiceBusListener()
{

    // setup subcsription
    var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
    if (!namespaceManager.SubscriptionExists("myTopic", Environment.MachineName))
        namespaceManager.CreateSubscription("myTopic", Environment.MachineName);

    SubscriptionClient busClient = SubscriptionClient.CreateFromConnectionString(connectionString, "myTopic", Environment.MachineName);

    // Configure the callback options.
    OnMessageOptions options = new OnMessageOptions();
    options.AutoComplete = false;
    options.AutoRenewTimeout = TimeSpan.FromMinutes(1);

    receiveTask = Task.Run(() =>
    {
        // handle new messages
        busClient.OnMessage((message) =>
        {
            try
            {
                Notification note = message.GetBody<Notification>();
                string notification = JsonConvert.SerializeObject(note);
                GlobalHost.ConnectionManager.GetHubContext<DispatchHub>().Clients.All.notify(notification);
                // Remove message from subscription.
                message.Complete();
            }
            catch (Exception)
            {
                // Indicates a problem, unlock message in subscription.
                message.Abandon();
            }
        }, options);
    }, cts.Token);
}