问题描述
我正在使用旧的SignalR v2.41
,但由于我也仅限于使用旧版本的MVC,因此必须使用它。除此之外,我还使用FluentScheduler
定期向客户端发送定向消息。
public class MyHub: Hub
{
public Dictionary<string,User> Connections { get; set; }
public MyHub()
{
Connections = new Dictionary<string,User>();
}
public override Task OnConnected()
{
// add connection
return base.OnConnected();
}
public override Task Ondisconnected(bool stopCalled)
{
// remove connection
return base.Ondisconnected(stopCalled);
}
}
现在,在FluentScheduler代码中,我需要掌握连接列表的中心,以便知道将哪个内容发送给哪个连接:
public class MyJob : IJob
{
public void Execute()
{
var hub = new DefaultHubManager(GlobalHost.DependencyResolver).ResolveHub("MyHub") as MyHub;
foreach (var conn in hub.Connections)
{
foreach (var msg in msgs)
{
hub.Clients.Client(conn.Key).send(msg);
}
}
}
}
问题是,我使用hub
获得的var hub = new DefaultHubManager(GlobalHost.DependencyResolver).ResolveHub("MyHub") as MyHub;
实例与客户端连接的实例不同,因为该实例从来没有任何连接。
如何获取正确的集线器实例?
解决方法
new
始终是一个新实例,因此您将永远无法获得连接客户端的集线器,因为您创建了一个新的集线器。
您应按以下方式解决中心问题:
static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
您也可以选中此question。
编辑:由于您需要向特定用户发送消息,因此我建议实现一个类以添加和删除连接,甚至更好的方法是映射users to groups。
建议始终注入IHubContext
而不是Hub
。引用SignalR开发人员在github上的话
您通常不应该用DI解决集线器。如果需要在集线器和其他组件之间共享代码,建议使用IHubContext或将共享代码放在单独的DI服务中。
此外,您也不应将集线器添加为单例:
SignalR希望分别为每个消息创建集线器。如果希望集线器位于DI中,则需要将其添加为Transient服务。
和
因为Hub类的实例是瞬态的,所以您不能使用它们来维护从一个方法调用到下一个方法调用的状态。每次服务器从客户端收到方法调用时,您的Hub类的新实例都会处理该消息。要通过多个连接和方法调用维护状态,请使用其他一些方法,例如数据库,Hub类上的静态变量,或者不是从Hub派生的其他类。
有关Hub object lifetime的更多文档。