IDisposable and Dependency Injection

I've seen a ton of confusion about this, both in comments on this blog and elsewhere. I have a post here where I present a generic repository. This class works with an Entity Framework context, but doesn't implement IDisposable.

The documentation on IDisposable is not great, unfortunately. The only advice Microsoft gives as to its usage is "Implement IDisposable only if you are using unmanaged resources directly." An "unmanaged resource" is simply something the garbage collector doesn't know about, like an open file or, more relevant to the example here, an open network connection to something like a database. That would seem to indicate that I should implement IDisposable, wouldn't it? Well, no, because that's only part of the story.

Yes, when working with something like an Entity Framework context, that context should be disposed: there's unmanaged resources in play. However, we need to also look at the concept of ownership. Who or what owns our context instance? Let's look at a quick example of something that implements IDisposable. I'm sure we've all seen code like this before:

public class FooController : Controller  
{
    private ApplicationDbContext db = new ApplicationDbContext();

    ...

    protected override void Dispose(bool disposing)
    {
        db.Dispose();
        base.Dispose(disposing);
    }
}

Here, you can see that Controller implements IDisposable and that the Dispose method is overridden to call Dispose on the context. As many of us in the ASP.NET MVC world were first introduced to MVC/Entity Framework with code like this, I think that's a source of much of the confusion. There's a feeling that you're supposed to dispose of the context. However, here, we did that because the controller owned the context. It newed it up, so the buck stops there.

Now let's look at the same controller utilizing dependency injection:

public class FooController : Controller  
{
    private ApplicationDbContext db;

    public FooController(DbContext db)
    {
        this.db = db;
    }

    ...
}

Where did the context come from? From the controller's perspective, it doesn't know. All it does know is that it was passed into its contructor. The question becomes: should the controller, then, dispose of the context? Well, to answer that, let's look at a more simplistic example:

var foo = new Foo();

var bar1 = new Bar(foo);  
var bar2 = new Bar(foo);

bar1.Dispose();  
bar2.Dispose();  

Here our Bar class has a dependency on Foo. We newed up two instances of Bar and passed the same instance of Foo into each. Then we disposed of both. What happens if Bar were to dispose of its Foo dependency? Well, now any other instances of Bar have a Foo instance that's been disposed. We've effectively broken those dependencies. Here, Bar doesn't own the Foo instance, so it should not dispose of it. To do otherwise will cause unforseen issues elsewhere in the system.

This is similar to how dependency injection works. In fact, this example is just manual dependency injection. When you use a DI container, it's just handling this automatically instead, but the same principle applies. The DI container is the owner of the objects it injects, and therefore, it should be the one that disposes of them.

The rule of thumb with implementing IDiposable pretty much boils down to this:

  1. Does this class own any of its dependencies? Does it new anything up?
  2. Do the dependencies this class owns implement IDisposable, themselves?

If you can answer "Yes" to both of those questions, go ahead and implement IDisposable. Otherwise, if the answer to either is "No", then you shouldn't implement IDisposable.

comments powered by Disqus