2

我正在使用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;与客户端连接的实例不同,因为这个实例从来没有任何连接。

如何获得正确的集线器实例?

4

1 回答 1

0

new始终是一个新实例,因此您将永远无法获得连接客户端的集线器,因为您创建了一个新集线器。

您应该像这样解决集线器:

static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();

你也可以检查这个问题

编辑:由于您需要向特定用户发送消息,我建议您实现一个类来添加和删除连接,甚至更好地将用户映射到组

建议您始终注入IHubContextHub. 来自 github 上 SignalR 开发人员的引用:

您通常不应该将集线器从 DI 中解析出来。如果您需要在 Hub 和其他一些组件之间共享代码,我建议使用 IHubContext 或将共享代码放在单独的 DI 服务中。

此外,您不应将 Hub 添加为单例:

SignalR 期望为每条消息单独创建集线器。如果您希望集线器处于 DI 中,则需要将其添加为瞬态服务。

因为 Hub 类的实例是瞬态的,所以您不能使用它们来维护从一个方法调用到下一个方法调用的状态。每次服务器接收到来自客户端的方法调用时,Hub 类的新实例都会处理该消息。要通过多个连接和方法调用来维护状态,请使用其他方法,例如数据库,或 Hub 类上的静态变量,或不是从 Hub 派生的不同类。

更多关于Hub 对象生命周期的文档。

于 2020-09-15T13:18:14.150 回答