dsuryd / dotNetify

Simple, lightweight, yet powerful way to build real-time web apps.
https://dotnetify.net
Other
1.17k stars 164 forks source link

Cannot access a disposed object - on refresh #132

Closed mojo-man closed 5 years ago

mojo-man commented 5 years ago

When I refresh my browser window, I encounter a number of "Cannot access a disposed object" exceptions. Is there any synchronization that I need to do to prevent this?

mojo-man commented 5 years ago
[1] [EXCEPTION - Visit Move] Cannot access a disposed object. (   at System.Reactive.DisposedObserver`1.OnNext(T value)
[1]    at DotNetify.ReactiveProperty`1.OnNext(T value)
[1]    at HME.Timer.Display.DisplayManager.ProcessVisitMessage(IMessage visitMsg) in C:\Content\Data\Dev\Janus-NewBaseline\DisplayServer\DisplayServer\DisplayManager.cs:line 262)
mojo-man commented 5 years ago

This seems to be happening since I updated to the latest version of dotnetify

dsuryd commented 5 years ago

The timer is trying to access a property of a view model instance that has been disposed (due the browser being refreshed). You should make sure the timer is also disposed as part of the view model dispose.

mojo-man commented 5 years ago

Which timer?

dsuryd commented 5 years ago

The timer that calls the view model property.

mojo-man commented 5 years ago

I am not using any timers - you are probably just seeing it in my namespace.

mojo-man commented 5 years ago

The "ProcessVisitMessage" is getting called from a different thread. That seems to be part of the problem.

mojo-man commented 5 years ago

I fire off a task in my constructor that receives messages via NetMQ.

dsuryd commented 5 years ago

Yes, when the VM Dispose is called, that thread needs to stop referencing the view model.

mojo-man commented 5 years ago

So - I need to kill that task from my OnDispose method?

dsuryd commented 5 years ago

One options is to emit a synchronization event to let that thread knows that the view model is being disposed, or to stop the thread altogether if that thread is only serving a single view model.

dsuryd commented 5 years ago

You mentioned that fire off the task in the constructor, so that task belongs to the view model instance, in which case, you can safely stop the task in the Dispose method.

mojo-man commented 5 years ago

That's what I am trying to do. Sending it a cancellation token.

mojo-man commented 5 years ago

Here is where I am starting my task (in the constructor):

            _tokenSource = new CancellationTokenSource();
            _token = _tokenSource.Token;

            _receiverTask = Task.Factory.StartNew(() =>
            {

               // create a receiver
               var _receiver = MessagingManager.GetMessageReceiver(_subscriptions);

               Console.WriteLine("Created receiver on port {0}", _receiver.ListenEndPoint.Port);

               // attach an event handler
               _receiver.OnReceiveMessage += _receiver_OnReceiveMessage;

               // start the receiver
               _receiver.Start();

            }, _token);

            Task.WaitAll(_receiverTask);

and here is where I am overriding Dispose.

        public override void Dispose()
        {
            _tokenSource.Cancel();
            _receiverTask.Dispose();
            base.Dispose();
        }
mojo-man commented 5 years ago

Still getting exceptions

dsuryd commented 5 years ago

You probably have a race condition if you're still seeing the exception. Make sure the thread will no longer call the property after the Dispose completes. Anyhow, I don't think this is an issue with dotNetify library itself.

mojo-man commented 5 years ago

Gotcha - Thanks again for your help Dicky!!

mojo-man commented 5 years ago

Not quite there yet - but making positive progress. Also need to add in correlation id - as in your chat example.