Extending Unity Container for IDisposable Instances (1st approach)
A few weeks ago, in my blog post ‘Who Disposes Your Repository’ I wrote about the challenges of implementing an IDisposable repository, which takes full advantage of the deferred execution of the IQueryable
In the end I have argued that especially for large applications, I would prefer that the Dependency Injection Container (DIC) disposes all the IDisposable
instances it created and it injected, including the repository. In short, the code that creates an IDisposable
instance should also be responsible to call Dispose()
on it.
In this post I will discuss some of the challenges of achieving this with Unity Container. By working to extend Unity with this functionality I have ended up implementing two approaches. In this post I will detail the first implementation I did, and in a next post I’ll explain the other.
There are many other writings on this. For example I have found useful the posts of Rory Primrose and of Marcel Veldhuizen who describe different approaches for disposing instances created by Unity. They both describe very well how Unity works and how it can be extended for this purpose. However, I was looking for an approach in which Unity remains unknown to the client code. I didn’t want the client code to call Teardown()
or other Unity specific methods.
I wanted that when an operation ends all the IDisposable
instances that were created and injected by Unity within that operation to be automatically disposed. Such an operation may be a request or a session in a web application, or may be a window or a view in a desktop one. In general any well-defined scope in any application.
My approach is based on using the Container Hierarchies (also known as Scoped Containers). Unity, as many other dependency containers, supports this. When you call CreateChildContainer()
method, it will create a container that inherits all the configurations form the current container. The idea is that when an operation begins, a child container will be created and associated with it. During that operation all the dependency injection will be done using the child container. This means that all the new instances injected during the operation, will be created by the child container. When the operation ends, the child container will be disposed. The Dispose()
of the child container should trigger the Dispose()
for all IDisposable
instances that were created.
Here is a good example on how to associate a child container with a web request on an ASP.NET MVC app or here for a WebApi app. I will come back in a future post on this, to show how this association can be done in a more abstract way which can also work when we are not in a web application. Now, I will dive into how to extend to trigger the Dispose()
from the child container to all the IDisposable
instances that it created.
The problem to solve boils down to these:
- Keep weak references to all the
IDisposable
instances that were created by the container (the child container) - Make sure that the
Dispose()
function of Unity will also callDispose()
on the instances we are referencing
The first thing I tried, was to make use of the lifetime managers. Unity defines this as an extension point to allow external code to control how references to object instances are stored and how the container disposes these instances. For example they are used to implement Singleton-like instances. When the container is configured, using RegisterType()
method, an instance of a LifetimeManager
has to be also given. The container will keep as part of its configuration, all the instances of the lifetime managers associated to the configured types, and it will call them when it injects instances of those types. A lifetime manager class is in general simple. It inherits the LifetimeManager
base class and by overriding GetValue()
and SetValue()
methods, it can control the lifetime of the instances of the type it was configured with.
For example if you want that a certain type to be Singleton like, you would use the ContainerControlledLifetimeManager
like this:
container.RegisterType<IMySingletonService, MySingletonService>(
new ContainerControlledLifetimeManager());
If we look into the codeof the ContainerControlledLifetimeManager
we see that the lifetime manager keeps a reference to the instance and it will return it each time GetValue()
is called (for simplicity I modified a bit the code of this class):
public class ContainerControlledLifetimeManager : LifetimeManager, IDisposable
{
private object value;
/// <summary>
/// Retrieve a value from the backing store associated with this Lifetime policy.
/// </summary>
/// <returns>the object desired, or null if no such object is currently stored.</returns>
public override object GetValue()
{
return this.value;
}
/// <summary>
/// Stores the given value into backing store for retrieval later.
/// </summary>
/// <param name="newValue">The object being stored.</param>
public override void SetValue(object newValue)
{
this.value = newValue;
}
/// <summary>
/// Remove the given object from backing store.
/// </summary>
public override void RemoveValue()
{
this.Dispose();
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this); // shut FxCop up
}
protected virtual void Dispose(bool disposing)
{
if (this.value != null)
{
if (this.value is IDisposable)
{
((IDisposable)this.value).Dispose();
}
this.value = null;
}
}
}
The first time an instance of MySingletonClass
needs to be injected, the Unity container will first call the GetValue()
of the lifetime manager. If that returns null
, the container will build a new instance, will call the SetValue()
of the lifetime manager to pass it back, and then it will inject it further. Next time an instance of same time is needed, the GetValue()
will return the previously created one, so the container will not build a new one. Therefore, the Singleton-like behavior.
The TransientLifetimeManger
is at the other end. It is used when you want new instances to be created each time they need to be injected. It is also the default. Its code is even simpler because GetValue()
always returns null, which makes the container to build new instances each time.
/// <summary>
/// An <see cref="LifetimeManager"/> implementation that does nothing,
/// thus ensuring that instances are created new every time.
/// </summary>
public class TransientLifetimeManager : LifetimeManager
{
/// <summary>
/// Retrieve a value from the backing store associated with this Lifetime policy.
/// </summary>
/// <returns>the object desired, or null if no such object is currently stored.</returns>
public override object GetValue()
{
return null;
}
/// <summary>
/// Stores the given value into backing store for retrieval later.
/// </summary>
/// <param name="newValue">The object being stored.</param>
public override void SetValue(object newValue)
{
}
/// <summary>
/// Remove the given object from backing store.
/// </summary>
public override void RemoveValue()
{
}
}
Unity design and documentation encourages using the lifetime managers to control the disposing of created instances. On its Dispose()
the container will call the Dispose()
on all the lifetime manager instances that implement IDisposable
. However, the TransientLifetimeManger
is not IDisposable
. This is somehow normal because it does not keep reference to anything, so nothing to Dispose()
. To achieve our goal, I have created a DisposableTransientLifetimeManger
like this:
public class DisposableTransientLifetimeManager : TransientLifetimeManager, IDisposable
{
private DisposableObjectList list = new DisposableObjectList();
public override void SetValue(object newValue)
{
base.SetValue(newValue);
IDisposable disposable = newValue as IDisposable;
if (disposable != null)
list.Add(disposable);
}
public void Dispose()
{
list.Dispose(); // this will call Dispose() on all the objects from the list
}
}
The SetValue()
will populate a list which keeps weak references to all instances which are disposable. On Dispose()
it will just dispose all the elements in the list. Simple. The ContainerControlledLifetimeManager
is already IDisposable
and it does dispose the instance it references. So now, if we use the disposable lifetime managers when we configure the container, all the instances which are IDisposable
be disposed when the container gets disposed.
This works fine when we dispose the container that is directly configured, with the disposable lifetime managers. However, what we wanted was to configure once the main container, and then to use child containers for each operation (request) and to dispose the child containers only. The child containers, would use the configuration of the parent. The code snippet below shows this usage case:
// configuring the main container
UnityContainer container = new UnityContainer();
container.RegisterType<IService1, Service1>(new DisposableTransientLifetimeManager());
container.RegisterType<IService2, Service2>(new DisposableTransientLifetimeManager());
using (var childContainer = container.CreateChildContainer()) // child container should be associated with an operation (request)
{
// some instances created within the operation (request)
s11 = childContainer.Resolve<IService1>();
s12 = childContainer.Resolve<IService1>();
s21 = childContainer.Resolve<IService2>();
s22 = childContainer.Resolve<IService2>();
} //childContainer.Dispose()
AssertIsDisposed(() => s11.Disposed); //–> fail
AssertIsDisposed(() => s12.Disposed); //–> fail
AssertIsDisposed(() => s21.Disposed); //–> fail
AssertIsDisposed(() => s22.Disposed); //–> fail
This does not work as we expected, because when the child container is disposed it does not have any lifetime managers instances in it. This is because it uses the configuration from the parent, including the instances of the lifetime mangers given there. This is by design in Unity. If the lifetime mangers instances from the parent would not be used, we would get into short lived singletons issues. Think that you configure a certain type to be Singleton. If you get objects of it through main container you get instance1
, but if you get it through a child container you would get instance2
. To prevent this, the same instance of lifetime manager (the one given at RegisterType()
is used by child containers too.
For our case, what we would like, is that for our disposable lifetime managers, the child container to create new instances of them and to use those to manage the lifetime of the objects it builds and injects. We can achieve this in by creating a custom Unity extension. Extensions are a more powerful way to extend the behavior of Unity and are often used in combination with the lifetime managers. As any powerful extension mechanism you can tweak the default behavior a lot, but when not used carefully you can work against the original design of the framework and create complexity. In our case we want to achieve the exact same thing as the HierarchicalLifetimeStrategy
does for the HierarchicalLifetimeManager
. So, I pretty much copied its code, into a new generic extension for any hierarchical lifetime manager, like this:
public class HierarchicalLifetimeExtension<T> : UnityContainerExtension where T : LifetimeManager, new()
{
protected override void Initialize()
{
Context.Strategies.AddNew<HierarchicalLifetimeStrategy<T>>(UnityBuildStage.Lifetime);
}
/// <summary>
/// A strategy that handles hierarchical lifetimes across a set of parent/child
/// containers.
/// </summary>
private class HierarchicalLifetimeStrategy<T> : BuilderStrategy where T : LifetimeManager, new()
{
/// <summary>
/// Called during the chain of responsibility for a build operation. The
/// PreBuildUp method is called when the chain is being executed in the
/// forward direction.
/// </summary>
public override void PreBuildUp(IBuilderContext context)
{
IPolicyList lifetimePolicySource;
var activeLifetime = context.PersistentPolicies.Get<ILifetimePolicy>(context.BuildKey, out lifetimePolicySource);
if (activeLifetime is T && !object.ReferenceEquals(lifetimePolicySource, context.PersistentPolicies) )
{
// came from parent, add a new lifetime manager locally
var newLifetime = new T();
context.PersistentPolicies.Set<ILifetimePolicy>(newLifetime, context.BuildKey);
context.Lifetime.Add(newLifetime);
}
}
}
}
Now, if we put all the pieces together, we get the behavior we wanted. The snippet below shows the result.
// configuring the main container
UnityContainer container = new UnityContainer();
container.RegisterType<IService1, Service1>(new DisposableTransientLifetimeManager());
container.RegisterType<IService2, Service2>(new DisposableTransientLifetimeManager());
var outterScopeSrv = container.Resolve<IService1>();
using (var childContainer = container.CreateChildContainer()) // child container should be associated with an operation (request)
{
// adding this extension to the child, makes the difference from previous code snippet
childContainer.AddExtension(
new HierarchicalLifetimeExtension<DisposableTransientLifetimeManager>());
// some instances created within the operation (request)
s11 = childContainer.Resolve<IService1>();
s12 = childContainer.Resolve<IService1>();
s21 = childContainer.Resolve<IService2>();
s22 = childContainer.Resolve<IService2>();
} //childContainer.Dispose()
AssertIsDisposed(() => s11.Disposed); //–> success
AssertIsDisposed(() => s12.Disposed); //–> success
AssertIsDisposed(() => s21.Disposed); //–> success
AssertIsDisposed(() => s22.Disposed); //–> success
AssertIsNotDisposed(() => outerScopeSrv.Disposed); //–> success
So, when the child container is disposed it will call the Dispose()
of all the IDisposable
lifetime mangers within the child container. The DisposableTransientLifetimeManager
we have created and use is IDisposable
and on its Dispose()
it will call the Dispose()
of all the IDisposable
instances that it references. The HierarchicalLifetimeExtension
that we have created and added to the child container, makes sure that when an instance is to be build, for a type that was configured in the parent container, a new instance of the same lifetime manager is created and added into the child container to be used from now on when building objects of that particular type.
This approach works well for transient lifetime manager and for most of the other lifetime managers, if are extended with the IDisposable
implementation in the same way. It is inline with the Unity design and not difficult to understand and use.
You can download all the source code in a zip file here.
However, this approach does not work for the PerResolveLifetimeManager
. Yes, it was a bad surprise for me too :(. PerResolveLifetimeManager
is not IDisposable
, but that’s not the issue. We could make a DisposablePerResolveLifetimeManager as we did for the transient, and collect in it weak references to all IDisposable
instances. However, the PerResolveLifetimeManager
behavior is implemented with the DynamicMethodConstructorStrategy
, and this is problematic. Under certain conditions this strategy creates new instances of the PerResolveLifetimeManager
. This seems to work against the original design of Unity, because by creating more new instances of a lifetime manager within same container instance, the lifetime manager is striped by its main purpose, which is to control the lifetime of the instances of a particular type. Here, the used instance of the lifetime manager is no longer given through RegisterType()
method, but it is being created during the object build. So, our current approach does not work for this lifetime manager for two main reasons: not all of the new instances of the PerResolveLifetimeManager
get stored into the container to be disposed, and the DynamicMethodConstructorStrategy
will build new instances of PerResolveLifetimeManager
not of DisposablePerResolveLifetimeManager
as we’d want.
For the cases when we would like to use both the PerResolveLifetimeManager
and the TransientLifetimeManger
I ended up making another implementation to extend Unity with same behavior of automatically disposing all the IDisposable
instances, when the child container gets disposed. I will detail it in a future post.