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();
}
}
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 theContext.ConnectionIdin your event.And don't use
Context.ConnectionIddirectly 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 storeContext.ConnectionIdand use that variable inside the event.