我从一个功能正常的SignalR Web应用程序开始,该应用程序具有从SignalR Hub派生的ActivityHub类来管理客户端连接和活动。与stock ticker tutorial类似,还有一个单独的ActivityTimer类,它使用System.Threading.Timer通过它在构造函数中获取的集线器上下文定期向所有客户端广播,如下所示:
activityHubContext = GlobalHost.ConnectionManager.GetHubContext<ActivityHub>();
现在我想将ActivityHub变成一个基类,其中包含用于不同类型活动的子类,在ActivityHub中覆盖一些用于特定于活动的行为的方法,以及使用特定于活动的客户端,每个客户端都引用相应的活动子class(例如,var activityHub = $ .connection.coreActivityHub)。
子分类适用于中心服务器代码和客户端,并且ActivityTimer按预期触发计时器事件,但ActivityTimer调用不再到达客户端。如果我获得特定活动子类的中心上下文,它将再次起作用,但仅适用于该子类:
activityHubContext = GlobalHost.ConnectionManager.GetHubContext<CoreActivityHub>();
有没有办法让一个通用的ActivityTimer能够与ActivityHub的所有子类一起使用? ActivityTimer可以调用基本ActivityHub类中的某个方法,而不是尝试直接访问所有客户端(基类似乎没有问题调用Clients.All.doSomething())?
如果它简化了事情(或者使得其他方面具有挑战性的解决方案),应用程序将一次只运行一种类型的活动 - 所有客户端将同时处于同一活动中。
答案 0 :(得分:0)
在处理同一项目中的其他问题时,我遇到this,其中指向this,我在其中找到了this(如果主题,我们都值得快速阅读感兴趣的你)。它们提供了一种方法来完成我想要做的事情:在基类中有一个方法可以从“外部”调用以到达任何/所有子类的客户端。 (他们还帮助我更清楚地思考了集线器上下文,以及为什么我认为我的原始ActivityTimer无法使用子类 - 请参阅本答案末尾的注释以获得进一步的解释。)
我的问题的解决方案是在基类中创建一个方法来调用客户端,然后从ActivityTimer调用这个新方法以间接地到达客户端。这种方法不依赖于ActivityTimer中的集线器上下文,它使我们不必担心子类,因为它明确地调用了基类:
在基类中创建一个静态字段以保存基类的集线器上下文:
private static IHubContext thisHubContext;
在每个子类的构造函数中使用该类作为传递给GetHubContext()的类型设置此中心上下文:
thisHubContext =
GlobalHost.ConnectionManager.GetHubContext<CoreActivityHub>();
在基类中创建一个静态方法,该方法调用所需的客户端方法;请注意,您可以使用除Clients.All之外的其他选项来访问客户端的子集(例如,arg可能指定要到达的SignalR组):
public static void DoSomething(string someArg)
{
thisHubContext.Clients.All.doSomething(someArg);
}
从集线器“外部”的任何服务器代码调用此基类方法。在我的例子中,我从ActivityTimer中的timer事件处理程序调用它:
ActivityHub.DoSomething("foo");
消息将传递给静态方法中指定的客户端。
注意:此解决方案仅适用于原始帖子末尾提到的特定情况,其中一次只使用一个子类,因为每个子类将基类静态集线器上下文设置为它自己的背景。我还没有试图找到解决这个限制的方法。
注意:我认为通过存储的集线器上下文使“外部集线器”服务器代码与子类一起工作是不可能的。在我原来运行的应用程序中(在我尝试创建ActivityHub的子类之前),ActivityTimer通过它实例化的集线器上下文与客户端进行对话:
public ActivityTimer()
{
activityHubContext = GlobalHost.ConnectionManager.GetHubContext<ActivityHub>();
activityTimer = new Timer(DoSomething, null, TimerInterval, TimerInterval);
}
public void DoSomething(object state)
{
activityHubContext.Clients.All.doSomething("foo");
}
因为集线器上下文是通过显式引用特定类(在本例中为ActivityHub)获得的,所以它不适用于子类。如果相反(正如我在原始帖子中提到的那样)我获得了特定子类的集线器上下文,计时器现在将用于那个子类的实例,而不是其他子类;同样,问题是为特定的子类获得了集线器上下文。
我认为没有办法解决这个问题,因此我认为唯一的解决方案是上面概述的解决方案,其中基类方法使用子类构造函数设置的集线器上下文,外部代码调用基础通过该子类上下文获取客户端的类方法。
但是,我仍然处于SignalR学习曲线(以及其他方面),所以将会感谢任何更正或澄清!