Using Ninject To Manage Critical Resources

This post does not pertain to the most recent (shortly after the release of this post) versions of Ninject. Ninject now handles the deactivation of all objects bound ‘InRequestScope’.

Recently a discussion with a reader led to this Stack Overflow question. Here is a summary of the problem:

The result is that the application eventually cannot connect to the database and fails.

The ‘InRequestScope’ binding ties the lifetime of the object to the instance of ‘HttpContext.Current’. Ninject deactivates objects when the object they are tied to gets garbage collected. Ninject uses an instance of a ‘WeakReference’ object coupled to a timer to determine if the garbage collector has run. It then purges the cached objects. A thorough post about Ninject’s lifecycle management was written previously by Nate Kohari.

I set up a test project to investigate a bit. I put a break point on the ‘Dispose’ method for the UnitOfWork instance. I then banged on the site by continually clicking refresh. I found the number of open database connections did indeed increase linearly with every request. The ‘Dispose’ break point was never reached. I then modified my code to include the following in my web application’s ‘EndRequest’ event:

void NinjectWebsiteApplication_EndRequest(object sender, System.EventArgs e)
{
    GC.Collect();
}

Now when I banged on the site, the ‘Dispose’ break point is reached and the connection thread count is under control.

Having all the evidence in front of me, it is now clear as to what is going on. Without the call to ‘GC.Collect’, garbage collection occurs too infrequently. Ninject’s implementation of life cycle management based upon garbage collection may not be able to manage the lifecycle of critical resources. Maybe I was naive to not take responsibility for such resources. For instance, I could easily control the ‘end of life’ for such critical resources by using the following code:

void NinjectWebsiteApplication_EndRequest(object sender, System.EventArgs e)
{
    var uow = Kernel.Get<IUnitOfWork>();
    uow.Dispose();
}

Here, I am fetching the UnitOfWork instance and manually calling dispose. This code does not seem ‘too bad’, but feels a bit like I am short-circuiting the purpose of using an IOC container. I want the container to be responsible for the lifetime of the objects. It seemed to me that the ‘InRequestScope’ binding could be handled better by Ninject. Why not register for the ‘EndRequest’ event and release all the ‘InRequestScope’ bindings?

I posted this to the Ninject group and as usual got a very prompt reply. The Ninject group has some amazing people who never sleep working on the project. Remo suggested adding the following to the ‘NinjectHttpApplication’

public abstract class NinjectHttpApplication : HttpApplication, IHaveKernel
{
    private static IKernel _kernel;

    protected NinjectHttpApplication()
    {
        EndRequest += NinjectHttpApplication_EndRequest;
    }

    protected static void NinjectHttpApplication_EndRequest(object sender, System.EventArgs e)
    {
        _kernel.Components.Get<ICache>().Clear(HttpContext.Current);
    }

    /* Other code removed for brevity */
}

After adding this code, the ‘UnitOfWork’ instances are collected at the end of every request. Remo mentioned that this will be included in an upcoming release of the Ninject MVC extension.

In the meantime, be aware of how critical resources are being managed by your IOC container. I am not sure how other containers work. I am very happy with Ninject and have a number of projects using the library. As I mentioned the Ninject community is amazing.

If you are using an IOC container, how do you manage critical resources?

Comments
  1. Rob
    • rcravens

Leave a Reply

Your email address will not be published. Required fields are marked *

*