Search code examples
c#mvvmgarbage-collectionobjectdisposedexception

How can I resolve inexplicable ObjectDisposedExceptions in my C# / MVVM application?


I've written my first MVVM application. When I close the application, I often get a crash cause by an ObjectDisposedException. The crash appears as the application dies, just after the app window disappears.

Getting a stacktrace was difficult (see my other question), but finally I did, and found that my stacktrace is entirely contained within C# libraries (kernel32!BaseThreadStart, mscorwks!Thread, mscorwks!WKS, etc).

Furthermore, this crash is inconsistent. After my last checkout and rebuild, it stopped happening... for a little while. Then it came back. Once it starts happening, it keeps happening, even if I "Clean" and rebuild. But a wipe-and-checkout sometimes makes it stop for a while.

WHAT I THINK IS HAPPENING:

I think the GarbageCollector is doing something funny when disposing my ViewModels. My ViewModelBase class destructor has a WriteLine to log when the destructor is called, and of my 4 ViewModels, only 2 or 3 get disposed, and it seems to vary depending on checkout (e.g. when I run it on mine, I see a consistently repeated sequence, but my colleague sees a different sequence with different objects disposed).

Since the stacktrace has none of my code's calls in it, I think that means that it's not my code that's calling a disposed object's method. So that leaves me thinking the CLR is being dumb.

Does this make sense? Is there some way I can get the GC to be consistent? Is this a red herring?

Other details that might help:
All of my Views and ViewModels are created in my App.xaml.cs file's Application's Startup event handler. That same handler assigns ViewModels to DataContexts. I'm not sure if this is correct MVVM practice (as I said, my first MVVM app), but I don't see why it would cause bad behavior.

I can paste code if necessary.


Solution

  • Your application is throwing an exception because your logging action on ViewModel destruction hasn't completed when your main application exits.

    You'll find that in order to perform the actual file writing a child process is spawned. If this hasn't completed by the time your main application has exited then you'll get an error.

    If you're going to perform this type of action then you need your main application to wait for a period for any child processes/threadpool threads etc. to complete before it exits.

    If you wish to ensure that you can log events that occur during your application closure then I would suggest that you run your logging process (the actual writing to your log file) as a separate primary thread that you post messages to. That way your application can close before your logging process has completed writing to disk.