Why does no one disposes DbContext after WebApi controller operation?
Asked Answered
E

6

12

I am aware of various tutorials as well as complete examples targeting WebApi & Entity Framework (even from Microsoft) that have WebApi controller like this:

public HttpResponseMessage GetInternet(int id) {
    var context = new InternetDbContext();
    var result =
       (from internet in context.Internets
        where internet.Id.Equals(id)
        select internet).FirstOrDefault();
    if(result != null)
       Request.CreateResponse(HttpStatusCode.OK, result);
}

But when I learnt about Entity Framework like 2 years ago, every resource I found about the framework pointed out how extremely important it is to DISPOSE the DbContex in the SHORTEST possible lifespan, e.g. with 'using'. And nowadays, people seem to don't give a shit about disposing anything (their managers, repositories, DI containers...).

Am I missing something here? Does the end of the API call automatically disposes the context? Or do I have to use something like HttpRequestMessageExtensions.RegisterForDispose() from http://msdn.microsoft.com/en-us/library/dn153859(v=vs.118).aspx?

Euhemerize answered 30/12, 2013 at 9:34 Comment(0)
D
9

Personally, whenever I see the type implements IDisposable, I'm almost certain that I'm going to use a using statement when working with new instances of this type.

When the variable goes out of scope (like in your case with the context variable going out of scope when the execution returns from GetInternet method), its memory is eventually going to be reclaimed by garbage collector but this doesn't mean that any native handlers (e.g. file handlers or database connections) are going to be closed which can have a very serious negative impact on your application.

So, consider always wrapping an IDisposable into the using construct:

using (var context = new InternetDbContext())
{
  // Your code goes here
}

Hope this helps.

Diverticulosis answered 30/12, 2013 at 9:44 Comment(4)
Just don't create HttpClient instances inside a using statement, even though it implements IDisposable.Slurry
@DarrelMiller Thanks, just went through this question. Ideally, I'd expect the type to encapsulate all the settings into another object (e.g. HttpRequestSettings) and still behave properly when I use it within the using statement - makes sense to keep the related TCP connection (pool) open until the object is disposed (plus, the connections are persistent by default with HTTP 1.1 so the pattern matches with what the protocol declares). But all this is probably a bit too complicated :-)Diverticulosis
Not sure I agree. Creating data objects to pass into other objects that you create, call and then destroy just seems like a return to functional programming. The fact that HttpClient implements IDisposable is for an exception scenario where your destroy the HttpClient whilst it is in the middle of a request and you need to clean up the cancellation token and the timeout timer.Slurry
Darrel, is there a benefit to not disposing a HttpClient?Dualistic
D
2

Sometimes it is a bad idea to dispose the context. For example, I have a WebAPI2 controller method like this,

    [Route("Questionnaires")]
    public IEnumerable<Questionnaire> GetAllQuestionnaires()
    {
        NMQContext context = new NMQContext();
        return context.Questionnaires.AsEnumerable();
    }

The result data is a JSON list, and the Questionnaire is a compound object -- it contains entities from multiple database tables. If I wrap this with "using" I get an error, such as

   "Message": "An error has occurred.",
   "ExceptionMessage": "The operation cannot be completed because the DbContext has been disposed.",

If you are trying to serialize compound objects, then it is better NOT to dispose the connection. It is better to let the EF handle it for you. You could probably fix it by explicit eager loading, but that is painful. Don't do it.

Devonadevondra answered 1/9, 2015 at 23:9 Comment(3)
Epilogue: I wrote this post in the naïveté of my youth. As you can see I am using DAO objects as DTO objects. In other words, I am returning EF objects from my web service. This is terrible and evil. Never do that. Always make different classes to define the DAO and DTO. And always use "using" to dispose the connection.Devonadevondra
I still think you are right. Even though you were to use separate DTOs the evaluation of the linq expression might happen later. To prevent that you'd always have to put it in a in-memory container.Prow
@JohnHenckel Isn't what you're missing here a simple .ToList() to execute the query?Toinette
G
1

Prime case for using, no matter how the method is exited, your DbContext will be disposed;

public HttpResponseMessage GetInternet(int id) {
    using(var context = new InternetDbContext()) {
        var result =
           (from internet in context.Internets
            where internet.Id.Equals(id)
            select internet).FirstOrDefault();
        if(result != null)
           Request.CreateResponse(HttpStatusCode.OK, result);
    }
}
Geanine answered 30/12, 2013 at 9:40 Comment(3)
Yes, this is what I initially learnt when I started working with EF. But it seems not a lot of people do this, especially not in tutorials. (I know tutorials tend to leave out a lot of things, but I can't recall seeing a context disposing anywhere while in basic EF tutorials, each tutorial had a big red hint to always dispose the context).Euhemerize
@Euhemerize With using, the DbContext/database connection is immediately disposed, otherwise you're leaving it up to garbage collection. Both will work, but you have no guarantee when the connection is released if not using using so it may be held on to for a longer time.Geanine
Out of my curiosity: How would you test GetInternet method with a test database if you have using statement?Brunabrunch
B
0

You are supposed to Dispose() of your context class, so use the using construct:

using (var context = new InternetDbContext())
{    
    // your code here, try/catch is auto-generated by the compiler
}
Berner answered 30/12, 2013 at 9:39 Comment(2)
Yes, this is what I initially learnt when I started working with EF. But it seems not a lot of people do this, especially not in tutorials. (I know tutorials tend to leave out a lot of things, but I can't recall seeing a context disposing anywhere while in basic EF tutorials, each tutorial had a big red hint to always dispose the context).Euhemerize
DbContext implements IDisposable, and therefore you have to use it, whether or not the current implementation actually requires it. The rule is plain and simple: if a class implements IDisposable, you have to Dispose() of its instances.Berner
A
0

It's because they're wrong. Don't trust other people's code, especially when it's part of an online tutorial.

Argentiferous answered 30/12, 2013 at 9:47 Comment(0)
H
-1

You should call Dispose() or use using when working with DbContext but you don't have to.

If you want to play safe, always wrap in a using or Dispose() but if you want to have a better understanding of EF DbContext implementation, keep reading.

Long story short, EF usually knows when is the time to Close a connection, so in the majority of the cases, call or not call Dispose() does the same result and doesn't have any impact in memory usage or performance because garbage collector will handle properly, unlike most of the IDisposable classes.

But, there are two main reasons that you should wrap in using or call Dispose() specifically for EF DbContext.

First is when someone manually open a connection with ObjectContext from the DbContext, if you don't call Dispose()/using you could leave open connections as those connections will not be managed automatically by EF.

The second reason is that the derived class of DbContextthat you are instantiating could be overriting the default behavior of dispose for example to aggregate the disposal of other unmanaged resources into the lifetime of the context, so if not properly disposed, it'll leave those resources alive.

This article is a must read.

Hesperides answered 11/3, 2015 at 16:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.