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:
- Does this class own any of its dependencies? Does it new anything up?
- 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
.