【问题标题】:SignalR, Push notification to connected clients based on event happening makes Hub disposedSignalR,根据事件发生向连接的客户端推送通知使 Hub 被处理
【发布时间】:2020-01-23 21:26:35
【问题描述】:

我正在尝试根据Asterisk PBX VOIP 服务器使用AsterNet ARI 发生的相关事件向已连接到SignalR Hub 的客户端推送通知。

我可以使用事件处理程序从 AsterNet 使用 DeviceStateChangedEvent 类获取事件,并希望向客户端推送与其设备状态更改相关的通知。

此外,SignalR 连接正常,欢迎消息显示在客户端网页上。

但问题是在通过 SendAsync 方法向调用方客户端发送通知时,我的 Hub 将被处置并引发以下异常:

System.ObjectDisposedException: '无法访问已处置的对象。 对象名称:'AgentHub'。'

这是我的 Hub 类,我重写了 OnConnectedAsync() 方法以发送欢迎消息并放置事件处理程序以侦听来自 PBX 的事件。

    public class AgentHub : Hub
    {
        public static AriClient ActionClient;

        public override async Task OnConnectedAsync()
        {
            ActionClient = new AriClient(
               new StasisEndpoint("voipserver", port, "username", "password"),
               "HelloWorld",
               true);

            ActionClient.Connect();

            ActionClient.OnDeviceStateChangedEvent += new DeviceStateChangedEventHandler(async delegate (IAriClient sender, DeviceStateChangedEvent e)
            {
                var notification = new DeviceStateChangeNotification
                {
                    NotificationText = e.Device_state.Name + "'s state changed to " + e.Device_state.State,
                    SentAt = DateTime.Now.ToString()
                };

                await Clients.Caller.SendAsync(
                    "ReceiveNotification",
                    notification.NotificationText,
                    notification.SentAt
                );
            });

            var notification = new DeviceStateChangeNotification
            {
                NotificationText = "Welcome!",
                SentAt = DateTime.Now.ToString()
            };

            await Clients.Caller.SendAsync(
                "ReceiveNotification",
                notification.NotificationText,
                notification.SentAt
            );

            await base.OnConnectedAsync();

        }
    }

【问题讨论】:

  • 与您的集线器被处置的问题无关,但我认为您的ActionClient 会有问题,因为它是静态的。每个连接的用户都会调用OnConnectedAsyc,因为ActionClient 是静态的,所以每次都会被覆盖。您可能应该有一个事件处理程序,可能在您的集线器的构造函数中订阅,并将处理程序发送到Clients.All
  • @JeffShepler 感谢,但将 ARIClient 移动到 Hub 构造函数时出现同样的错误。我认为根据github.com/aspnet/SignalR/issues/2424#issuecomment-394198451 的问题是我无法从范围之外访问 Hub。

标签: c# asp.net-core-signalr asterisk-ari


【解决方案1】:

集线器是短暂的,它们仅在集线器方法执行时存在。这里发生的是您正在为捕获“this”(集线器)的 OnDeviceStateChangedEvent 创建一个事件。稍后触发事件时,您将尝试访问该方法退出后立即释放的 Hub。

为了正确执行此操作,您需要在 Hub 的构造函数中注入 IHubContext<AgentHub>,然后将其和 Context.ConnectionId 存储在您的事件中。

并且不要在您的活动中直接使用Context.ConnectionId,因为这样会捕获“this”并遇到同样的问题。相反,您可以在 hub 方法内的事件外部创建一个变量来存储 Context.ConnectionId 并在事件内使用该变量。

【讨论】:

    猜你喜欢
    • 2020-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多