我使用的是旧的SignalR v2.41,但我必须使用它,因为我也只能使用旧版本的MVC。除此之外,我还使用FluentScheduler每隔一段时间向客户端发送目标消息。
问题是,我在我的Hub中保存了一个用户连接字典:
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);
}
}
}
}问题是,我使用var hub = new DefaultHubManager(GlobalHost.DependencyResolver).ResolveHub("MyHub") as MyHub;获得的hub实例与客户端连接的实例不同,因为这个实例从来没有任何连接。
如何获取正确的集线器实例?
发布于 2020-09-15 21:18:14
new总是一个新实例,因此您永远不会获得客户端所连接的集线器,因为您正在创建一个新的集线器。
您应该像这样解析集线器:
static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();您还可以检查此question。
编辑:由于您需要向特定用户发送消息,因此我建议实现一个类来添加和删除连接,或者更好地实现映射users to groups。
建议您始终注入IHubContext而不是Hub。引用github上一位SignalR开发人员的话:
你一般不应该把集线器从依赖注入中解析出来。如果您需要在Hub和其他组件之间共享代码,我建议使用IHubContext或将共享代码放在单独的DI服务中。
此外,您不应该将集线器添加为单例:
SignalR希望为每个消息单独创建集线器。如果您希望您的Hub位于DI中,则需要将其添加为临时服务。
和
因为Hub类的实例是暂时的,所以您不能使用它们来维护从一个方法调用到下一个方法调用的状态。每次服务器接收到来自客户端的方法调用时,Hub类的新实例都会处理该消息。要通过多个连接和方法调用来维护状态,请使用其他方法,如数据库,或者Hub类上的静态变量,或者不是从Hub派生的其他类。
有关Hub object lifetime的更多文档。
https://stackoverflow.com/questions/63901322
复制相似问题