0
votes

I'm trying to push notifications to clients who have connected to SignalR Hub based on related events are happening in Asterisk PBX VOIP server using AsterNet ARI.

I can get events using DeviceStateChangedEvent class from AsterNet using an event handler and want to push notification to clients related to their devices' state changes.

Also, SignalR connection is working as well and welcome message is showing on client web page.

But the problem is while sending notification by SendAsync method to caller client, my Hub goes to be disposed and below exception raised:

System.ObjectDisposedException: 'Cannot access a disposed object. Object name: 'AgentHub'.'

Here is my Hub class which I've overridden the OnConnectedAsync() method to send welcome message and put event handler for listening events from 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();

        }
    }
1
Not related to the issue with your hub getting disposed, but I think you're going to have issues with your ActionClient because it's static. The OnConnectedAsyc is called for each user that connects and because ActionClient is static, it will get overwritten each time. You should probably have a single event handler, maybe subscribed in your hub's constructor, and have the handler send to Clients.All.Jeff Shepler
@JeffShepler thanks but same error with moving ARIClient to Hub constructor. I think according to github.com/aspnet/SignalR/issues/2424#issuecomment-394198451 the problem is I have no access to Hub from outside of scope.Mehdi

1 Answers

0
votes

Hubs are short lived, they only exist while the hub method is being executed. What's happening here is that you are creating an event for OnDeviceStateChangedEvent which captures "this" (the Hub). Later when the event is triggered, you are trying to access the Hub which was disposed as soon as the method exited.

In order to properly do this, you need to inject IHubContext<AgentHub> in the constructor of the Hub and then store that and the Context.ConnectionId in your event.

And don't use Context.ConnectionId directly in your event because that will capture "this" and have the same issue. Instead you can make a variable outside the event inside the hub method to store Context.ConnectionId and use that variable inside the event.