Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework, DBContext and using() + async?

Tags:

There is a thing that's been bugging me for a long time about Entity Framework.

Last year I wrote a big application for a client using EF. And during the development everything worked great.

We shipped the system in august. But after some weeks I started to see weird memory leaks on the production-server. My ASP.NET MVC 4 process was taking up all the resources of the machine after a couple of days running (8 GB). This was not good. I search around on the net and saw that you should surround all your EF queries and operations in a using() block so that the context can be disposed.

In a day I refactored all my code to use using() and this solved my problems, since then the process sits on a steady memory usage.

The reason I didn't surround my queries in the first place however is that I started my first controllers and repositories from Microsofts own scaffolds included in Visual Studio, these did not surround it's queries with using, instead it had the DbContext as an instance variable of the controller itself.

First of all: if it's really important to dispose of the context (something that wouldn't be weird, the dbconnection needs to be closed and so on), Microsoft maybe should have this in all their examples!

Now, I have started working on a new big project with all my learnings in the back of my head and I've been trying out the new features of .NET 4.5 and EF 6 async and await. EF 6.0 has all these async methods (e.g SaveChangesAsync, ToListAsync, and so on).

public Task<tblLanguage> Post(tblLanguage language) {     using (var langRepo = new TblLanguageRepository(new Entities()))     {         return langRepo.Add(RequestOrganizationTypeEnum, language);     } } 

In class TblLanguageRepo:

public async Task<tblLanguage> Add(OrganizationTypeEnum requestOrganizationTypeEnum, tblLanguage language) {     ...     await Context.SaveChangesAsync();     return langaugeDb; } 

However, when I now surround my statements in a using() block I get the exception, DbContext was disposed, before the query has been able to return. This is expected behaviour. The query runs async and the using block is finished ahead of the query. But how should I dispose of my context in a proper way while using the async and await functions of ef 6??

Please point me in the right direction.

Is using() needed in EF 6? Why do Microsoft's own examples never feature that? How do you use async features and dispose of your context properly?

like image 251
Objective Coder Avatar asked Feb 07 '14 15:02

Objective Coder


1 Answers

Your code:

public Task<tblLanguage> Post(tblLanguage language) {     using (var langRepo = new TblLanguageRepository(new Entities()))     {         return langRepo.Add(RequestOrganizationTypeEnum, language);     } } 

is disposing the repository before returning a Task. If you make the code async:

public async Task<tblLanguage> Post(tblLanguage language) {     using (var langRepo = new TblLanguageRepository(new Entities()))     {         return await langRepo.Add(RequestOrganizationTypeEnum, language);     } } 

then it will dispose the repository just before the Task completes. What actually happens is when you hit the await, the method returns an incomplete Task (note that the using block is still "active" at this point). Then, when the langRepo.Add task completes, the Post method resumes executing and disposes the langRepo. When the Post method completes, the returned Task is completed.

For more information, see my async intro.

like image 73
Stephen Cleary Avatar answered Oct 02 '22 11:10

Stephen Cleary