Do I always have to call Dispose() on my DbContext objects? Nope

Like I mentioned in my post “Microsoftie Perk #9 – Access to product team devs“, it is awesome to be able to ping the guys who build the tools we use every day. This post is a great example of that perk. The EF team has been amazing, especially Rowan Miller and Diego Vega. Always very positive and eager to help out. This post is about my research into a question that has always been lingering in the back of my mind….

“Should I always call Dispose() on my DbContext objects?”

Before I talked with the devs on the EF team my answer was always a resounding “of course!”. But it’s not true with DbContext. You don’t need to be religious about calling Dispose on your DbContext objects. Even though it does implement IDisposable, it only implements it so you can call Dispose as a safeguard in some special cases. By default DbContext automatically manages the connection for you. Read to the end to hear the full story and see what the EF devs had to say about it.

(Showing that DbContext implements IDisposable)

I started the conversation with the EF team by proclaiming that the industry needs to stop teaching people to use DbContext objects as private members without disposing of them properly. Rowan Miller‘s first response, was that yes, we do encourage it and try to make sure we dispose of all our DbContext objects anytime we have a demo or sample code. So I thought “yes, I’m right!” let me code up an example that demonstrates to my blog readers the difference calling Dispose makes to our User Connections count. So I setup perfmon to monitor User Connections and ran the sample below. I was surprised to see that the User Connection numbers were exactly the same. I didn’t matter if I called Dispose or not!

static void Main(string[] args)
{
bool useUsing = args.Length == 0 || bool.Parse(args[0]);
Call(useUsing);
}
private static void Call(bool useUsing)
{
for (int i = 0; i < 5000; i++)
{
if (useUsing)
{
using (var db = new DbContextUsingTestEntities())
{
CallInternal(db);
}
}
else
{
var db = new DbContextUsingTestEntities();
CallInternal(db);
}
}
}
private static void CallInternal(DbContextUsingTestEntities db)
{
var data = from d in db.Data select d;
foreach (var datum in data)
{
Console.WriteLine(string.Concat(datum.Id, ":", datum.Name));
}
}

So I pinged Rowan again with my code snippet to see if they had any other code samples that accurately demonstrated the effect on User Connections. In the meantime I was watching the MVC4 PluralSight course and saw Scott Allen use a DbContext object without calling Dispose. I thought, man I totally respect Scott Allen and if he’s not calling Dispose then something must be wrong with my thinking, so I sent this along to Rowan as well.

clip_image002

Rowan forwarded my mail to Diego Vega (the Senior SDE Lead on EF) and here is his response

Hello Jon,

The default behavior of DbContext is that the underlying connection is automatically opened any time is needed and closed when it is no longer needed. E.g. when you execute a query and iterate over query results using “foreach”, the call to IEnumerable<T>.GetEnumerator() will cause the connection to be opened, and when later there are no more results available, “foreach” will take care of calling Dispose on the enumerator, which will close the connection. In a similar way, a call to DbContext.SaveChanges() will open the connection before sending changes to the database and will close it before returning.

Given this default behavior, in many real-world cases it is harmless to leave the context without disposing it and just rely on garbage collection.

That said, there are two main reason our sample code tends to always use “using” or dispose the context in some other way:

1. The default automatic open/close behavior is relatively easy to override: you can assume control of when the connection is opened and closed by manually opening the connection. Once you start doing this in some part of your code, then forgetting to dipose the context becomes harmful, because you might be leaking open connections.

2. DbContext implements IDiposable following the recommended pattern, which includes exposing a virtual protected Dispose method that derived types can override if for example the need to aggregate other unmanaged resources into the lifetime of the context.

By the way, with DbContext the pattern to open the connection manually and override the automatic open/close behavior is a bit awkward:

((IObjectContextAdapter)dbContext).ObjectContext.Connection.Open()

But we have a bug to make this easier as it used to be with ObjectContext before, e.g.:

dbContext.Database.Connection.Open()

Hope this helps,

Diego

So there you have it. DbContext manages the underlying connection for you. You can call Dispose, but in most common scenarios you don’t need to. I’m old school, so I still call Dispose, but it’s great knowing for sure that you don’t have to.

Hope this helps those who were curious about why you don’t see people calling Dispose or using the using statement all the time. Maybe it is out of laziness, but at least EF has them covered.

Jon