使用 SignalR 中的正确上下文从另一个集线器调用一个集线器

Calling one hub from another hub with the correct context in SignalR

我有两个集线器,一个用于跟踪用户 (chatHub),另一个用于仪表板 (dashHub)。

当新用户连接到该网站时,它会触发 Server.Connect 跟踪用户 ID 和组的方法。然后我想从 ChatHub 调用 DashHub.Update(),以便所有 dash 订阅者都能获得推送给他们的新数据。

I have read this on the official documentation 并理解那里发生了什么,但我真的想调用 DashHub.Update() 方法,其中有一些逻辑,而不仅仅是通过上下文发送消息。环顾 Whosebug 和其他示例,我找到了这个可行的解决方案,但它看起来并不正确。

ChatHub.cs - 每次我需要将数据推送到仪表板时都会调用 UpdateDashboardClients()。它是私人的。

private void UpdateDashboardClients()
{
      DashHub dh = new DashHub();
      dh.SendNew();
} 

DashHub.cs - 这在 dashbpaord 客户端和我解决 Context == null 从集线器外部调用时问题的解决方案上工作正常,从另一个集线器我使用了这个。

 public void SendNew()
 {
    if (Context == null)
    {
       IHubContext contextDashHub =  GlobalHost.ConnectionManager.GetHubContext<DashHub>();
       contextDashHub.Clients.Clients(<clients>).PushNew(<data>)
    }
    else
    {
        Clients.Clients(<clients>).PushNew(<data>);
    }

 }

我试图通过强制转换将已解析的 IHubContext contextDashHub 设置为 this.Context 但失败了,因为 this.Context 的类型为 HubCallerContext.

如果我可以制作另一个采用上下文的构造函数,或者只是一个采用上下文并将其分配给 dashhub 上下文的方法,那就太好了。

我在服务器上阅读了一些关于代理的内容,但不确定它是如何工作的,也不确定它是否是正确的方法。

这个 "workaround" 现在对我有用,但它的可重用性不是很好,而且它重复代码,这使它很臭。

我想我需要以某种方式使用来自 ChatHub 的 DI(类似于获取上下文)来正确执行此操作,但我在 DI 方面还是相当新,不确定具体如何操作。

任何人都可以提供正确的方法来做到这一点。

正如您已经注意到的,您尝试做的不是正确的方法。事实上,您真的想自己实例化一个集线器并调用它的方法是错误的。集线器实例的生命周期应由 SignalR 的运行时控制。

你得到一个空上下文的事实是完全合乎逻辑的,你不应该试图改变它,否则它就没有意义。例如,如果您的 hub 中有代码正在检查 Caller 端点,那么即使从逻辑角度来看也无法正常工作(在这种情况下没有调用者)。你永远不应该尝试这样的 hack,因为你无法构建适用于所有情况的上下文。

您应该检查您的体系结构,将处理客户端请求的内容与直接在服务器上发起的广播相关的内容分开。将它们视为 2 个不同的职责,并相应地构建您的代码。您可能会基于 IHubContext 为服务器端消息引入 "broadcast service",例如,您可能有来自集线器方法的代码通过将它们自己的上下文传递给它来调用此服务。该服务不知道调用是由客户端还是服务器代码发起的,它将是可重用的并且没有重复。

DI 可以帮助您保持此类代码的整洁,但这并不是绝对必要的。它还取决于您的应用程序的大小,但如果它只是一堆类型,您可以采取一些快捷方式并仍然控制代码。否则,SignalR 的 DI 支持并不难管理,阅读它,您会发现它非常容易。如果你使用 DI,你可能会让你的集线器接收广播服务的实例(总是相同的实例还是总是新的?它可以双向工作,这取决于它是如何实现的)并相应地在它们的方法调用中使用它,通过在每个案例的正确上下文中。