I'm using MEF as the IoC container in WPF with Caliburn.Micro framework. The MEF container resides in the Bootstrapper
. Bootstrapper
has the method:
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<ViewModels.Main.MainViewModel>();
}
Now, the MainViewModel
has this:
private IEnumerable<ExportFactory<Screen>> _screenList { get; set; }
[ImportingConstructor]
public MainViewModel(IEventAggregator eventAggregator, [ImportMany] IEnumerable<ExportFactory<Screen>> screenList)
{
_screenList = screenList;
eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);
}
The class basically has an IEnumerable
of ExportFactory
. A Screen
is basically a ViewModel
that inherits from VMBase
which in turn inherits from Screen
. Now, some of those ViewModel
use a Unit of Work, which, in turn, has a DbContext
injected into it via the constructor
.
So basically, the dependency chain is like this:
DbContext -> UnitOfWork (IDisposable) -> ViewModelBase(IDisposable) -> ViewModels
. These ViewModel
are instantiated using the ExportFactory
in the MainViewModel
.
The MainViewModel
is subscribed to the eventAggregator
, and Handler
of MainViewModel
calls the ExportFactory
to create a new instance of a ViewModel
as necessary. The problem is, when that ViewModel
is closed, the DbContext
is not properly disposed of.
This is the Handle
method:
public void Handle(Type message)
{
DeactivateItem(ActiveItem, true);
ActivateItem(screenList.FirstOrDefault(c => c.CreateExport().Value.GetType() == message).CreateExport().Value);
}
This creates new instances of DbContext
, but doesn't call Dispose()
of ViewModelBase
ever, as I verified using breakpoints.
I tried changing the Handle
method to call Dispose()
like this:
DeactivateItem(ActiveItem, true);
_currentLifetimeContext?.Dispose();
_currentLifetimeContext = _screenList.FirstOrDefault(c => c.CreateExport().Value.GetType() == message).CreateExport();
ActivateItem(_currentLifetimeContext.Value);
but it throws an error "The operation cannot be completed because the DbContext has been disposed."
How can I properly dispose of the DbContext
in my application?
It is almost impossible to state why your code is failing without testing it in its entirety. However, in my limited experience with MEF, I have found that most of the disposal problems are created when the exports are not explicitly marked to be NonShared
. This is one of the annoyances of MEF, where it treats all components to be singleton by default. My advice is to explicitly mark each and every export of yours to be NonShared
, unless you want a singleton. Not just the ViewModels
. Let us know if it works.