I have a simple wrapper for a Unity IoC container (a temporary use of Service Locator [anti-]Pattern to introduce DI to a legacy codebase), and since the IUnityContainer
in Unity implements IDisposable
I wanted to expose that through the wrapper as well.
The wrapper is simple enough:
public class IoCContainer : IIoCContainer
{
private IUnityContainer _container;
public IoCContainer(IUnityContainer container)
{
_container = container;
}
public T Resolve<T>()
{
return _container.Resolve<T>();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~IoCContainer()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
if (_container != null)
{
_container.Dispose();
_container = null;
}
}
}
IIoCContainer
is the domain interface which has nothing but T Resolve<T>()
on it, and of course IDisposable
. So everything below that one method is simply the implementation of IDisposable
as I found it on MSDN.
However, when .Dispose()
is called on this object (such as when exiting a using
block), a StackOverflowException
is raised. Debugging, it looks like the call stack repeats between:
Dispose()
is called on this classDispose(true)
on this classDispose()
on IUnityContainer
Dispose()
on this classI can resolve this in this case by putting a bool
flag on the class, setting it on the first line of Dispose()
, and checking for it in Dispose(bool)
, so the recursion ends at its second iteration. But why does this happen in the first place? I can only assume I've either missed something obvious or misunderstood something about resource disposal. But what?
This is implementation of IDisposable
within UnityContainer
. It is obvious that you cannot dispose your parent container. It will iterate through all registrations and dispose them if they are also IDisposable
. Take a look:
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (lifetimeContainer != null)
{
lifetimeContainer.Dispose();
lifetimeContainer = null;
if (parent != null && parent.lifetimeContainer != null)
{
parent.lifetimeContainer.Remove(this);
}
}
extensions.OfType<IDisposable>().ForEach(ex => ex.Dispose());
extensions.Clear();
}
}
I believe the problem here is that you are not supposed to be disposing of the container instance that implements IUnityContainer
within your class.
The instance is being passed on as a resource to your class, but it was created externally, so whatever code created that instance is the one that should be in charge of disposing of it properly.
Your IoCContainer
should only be concerned with disposing of resources it creates internally.
This is not the best answer probably, but if you have no controll over implementation of IUnityContainer
and it have to dispose IoCContainer
you can always break the chain of recurrection in at least two, valid ways:
protected virtual void Dispose(bool disposing)
{
if (disposing)
if (_container != null)
{
var tempContainer = _container;
_container = null;
tempContainer.Dispose();
}
}
or
private bool isDisposed = false;
protected virtual void Dispose(bool disposing)
{
if(isDisposed) return;
isDisposed = true;
if (disposing)
if (_container != null)
{
_container.Dispose();
_container = null;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With