0

I'm basically trying to do some database work if the user has been disconnected from signalR for more than 10 minutes. I put a timer in the Hub's OnDisconnectedAsync(). The issue I'm running into is ObjectDisposedException on things that I need to access the database. I get the same problems when I bypass the timer and try to make the calls directly in OnDisconnectedAsync(). I guess everything has been destroyed by the time I make it into OnDisconnectedAsync().

I've been trying everything I can find for days, but nothing seems to work. What is the correct way to handle this kind of problem?

public class RangeHub : Hub
{
    private readonly IHubContext<RangeHub> _hubContext;
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly IDashboardService _service;
    private readonly ApplicationDbContext _context;
    private readonly ISubscriptionService _subscription;
    private readonly HOptions _hOptions;
    //private Timer disconnectTimer = new Timer();
    private CustomTimer disconnectTimer;

    private string UserId
    {
        get
        {
            //return User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier).Value;
            return Context.UserIdentifier;
        }
    }

    public RangeHub(IHubContext<RangeHub> hubContext, UserManager<ApplicationUser> userManager, IDashboardService service, ApplicationDbContext context,
                               ISubscriptionService subscription, IOptionsMonitor<HOptions> hOptions)

    {
        _hubContext = hubContext;
        _context = context;
        _userManager = userManager;
        _service = service;
        _subscription = subscription;
        _hOptions = hOptions.CurrentValue;

        disconnectTimer = new CustomTimer
        {
            Interval = 30000,
            AutoReset = false
        };
        disconnectTimer.Elapsed += DisconnectTimedEvent;
        //disconnectTimer.Elapsed += (sender, e) => DisconnectTimedEvent(sender, e, UserId);
        //disconnectTimer.Interval = 30000;//120000;
        //disconnectTimer.AutoReset = false;
    }

    public override Task OnConnectedAsync()
    {
        Log.Information("OnConnectedAsync: CONNECT TO CLIENT");
        System.Diagnostics.Debug.WriteLine("OnConnectedAsync: CONNECT TO CLIENT");

        //If timer was running, stop timer/reset
        if(disconnectTimer.Enabled)
        {
            //reset timer
            disconnectTimer.Stop();
        }

        return base.OnConnectedAsync();
    }

    public override Task OnDisconnectedAsync(Exception exception)
    {
        //TODO: This is firing off when the dashboard is left, need to fix
        Log.Information("OnDisconnectedAsync: DISCONNECTED FROM CLIENT");
        System.Diagnostics.Debug.WriteLine("OnDisconnectedAsync: DISCONNECTED FROM CLIENT");
        _service.StopActiveEnvironment(UserId);
        //_hubContext.Clients.
        //TODO: place logic here to stop environment and stop user's time
        disconnectTimer.userId = UserId;
        disconnectTimer.dashService = _service;
        disconnectTimer.dBContext = _context;
        //disconnectTimer.Start();
        //*is this for a single user? will this effect all users at once?

        return base.OnDisconnectedAsync(exception);
    }

    public void DisconnectTimedEvent(object sender, ElapsedEventArgs e)//, IDashboardService dashService)
    {
        //Shut down the range
        Log.Information("DEBUG Timer");
        Log.Information("UserId: " + ((CustomTimer)sender).userId);
        Log.Information("Shutting down environment due to signalR disconnection timer.");

        //Van - 9-28-2019: Not using await here. This should be the last thing done before the instance of this class is destroyed.
        //  Using await takes too long and the Hub object is already destroyed before its finished.
        //_service.StopActiveEnvironment(((CustomTimer)sender).userId);
        //Task.Run(async () => await _service.StopActiveEnvironment("051735c4-fa6d-4d90-9f76-b540aaa110bc"));
        //Task.Run(async () => await _service.StopActiveEnvironment("051735c4-fa6d-4d90-9f76-b540aaa110bc")).WaitAndUnwrapException();
        try
        {
            var func = ((CustomTimer)sender).dashService.StopActiveEnvironment(((CustomTimer)sender).userId);
            func.WaitAndUnwrapException();
        }
        catch (Exception ex)
        {
            Log.Error(ex.ToString());
        }
    }
}

class CustomTimer : Timer
{
    public string userId;
    public IDashboardService dashService;
    public ApplicationDbContext dBContext;
}
Snipe3000
  • 321
  • 3
  • 15
  • You can call the disconnected method and set a timer like you have and each second listen if it has been connected. Then after timeout you can do your DB stuff... – Kiril1512 Sep 30 '19 at 08:51
  • Which disconnected method are you referring to? – Snipe3000 Sep 30 '19 at 23:25
  • You have the OnDisconected method. Then you call the timeout timer. When this method is hit, you set your timer and after 10 minutes you do your DB stuff. You also have the OnReconected method which you can use to destroy the timer. – Kiril1512 Oct 01 '19 at 08:40

0 Answers0