5

I have several classes based on System.Entity.Data.DbContext. They get used several times a request in disparate ends of the web application - is it expensive to instantiate them?

I was caching a copy of them in HttpContext.Current.Items because it didn't feel right to have several copies of them per request, but I have now found out that it doesn't get automatically disposed from the HttpContext at the end of the request. Before I set out writing the code to dispose it (in Application_EndRequest), I thought I'd readdress the situation as there really is no point caching them if I should just instantiate them where I need them and dispose them there and then.

Questions similar to this have been asked around the internet, but I can't seem to find one that answers my question exactly. Sorry if I'm repeating someone though.

Update

I've found out that disposing of the contexts probably doesn't matter in this blog post, but I'm still interested to hear whether they are expensive to instantiate in the first place. Basically, is there lots of EF magic going on there behind the scenes that I want to avoid doing too often?

sjmeverett
  • 1,196
  • 10
  • 21
  • Another SO answer basically answers my question: [here](http://stackoverflow.com/questions/813457/instantiating-a-context-in-linq-to-entities). In order to speed up the creation a bit though it is possible to use a cached EntityConnection as per [this](http://stackoverflow.com/questions/2575485/managing-entityconnection-lifetime) question (although it's useful to bear in mind that it is not thread safe). I can't answer my own question yet, so I'll wait and see if there are any other candidates. – sjmeverett Jul 05 '11 at 11:44
  • possible duplicate of [One DbContext per web request... why?](http://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why) – Steven Apr 02 '14 at 13:07

4 Answers4

6

Best bet would be to use an IoC container to manage lifecycles here -- they are very, very good at it and this is quite a common scenario. Has the added advantage of making dynamic invocation easy -- meaning requests for your stylesheet won't create a DB context because it is hardcoded in BeginRequest().

Wyatt Barnett
  • 15,444
  • 3
  • 31
  • 51
4

I'm answering my own question for completeness.

This answer provides more information about this issue.

In summary, it isn't that expensive to instantiate the DbContext, so don't worry.

Furthermore, you don't really need to worry about disposing the data contexts either. You might notice ScottGu doesn't in his samples (he usually has the context as a private field on the controller). This answer has some good information from the Linq to SQL team about disposing data contexts, and this blog post also expands on the subject.

Community
  • 1
  • 1
sjmeverett
  • 1,196
  • 10
  • 21
3

Use HttpContext.Items and dispose your context manually in EndRequest - you can even create custom HTTP module for that. That is a correct handling. Context disposal will also release references to all tracked entities and allow GC collecting them.

You can use multiple context per request if you really need them but in most scenarios one is enough. If your server processing is one logical operation you should use one context for whole unit of work. It is especially important if you do more changes in transaction because with multiple context your transaction will be promoted to distributed and it has negative performance impact.

Ladislav Mrnka
  • 349,807
  • 56
  • 643
  • 654
  • Thanks. I don't understand the bit about "your transaction will be promoted to distributed" could you clarify please? Do you _need_ to dispose the context though? The blog post mentioned in the updated question seems to suggests otherwise, and I've noticed Scott Gu tends to use private fields for his contexts, which don't then get disposed. – sjmeverett Jul 05 '11 at 11:53
  • The point @Ladislav has been particularly pertinent to us. We rely on multiple contexts withing transaction scopes, which of course cause the transactions' promotion through the DTC. However, we still found that the entity sets were being cleaned efficiently enough to not require forcing the contexts to dispose. I understand it isn't _efficient_ programming, or _best practice_, but it does _just work_. There was also a perculiar side effect when we did enforce disposal of contexts in that what should have been independant instances of the same context, being using async, died on us... – Smudge202 Jul 05 '11 at 12:09
0

We have a web project using a similar pattern to the one you've described (albeit with multiple and independant L2S Contexts instead of EF). Although the context is not disposed at the end of the request, we have found that because the HttpContext.Current becomes unreferenced, the GC collects the context in due course, causing the dispose under the scenes. We confirmed this using a memory analyser. Although the context was persisting a bit longer than it should, it was acceptable for us.

Since noticing the behaviour we have tried a couple alternatives, including disposing the contexts on EndRequest, and forcing a GC Collect on EndRequest (that one wasn't my idea and was quickly receded).

We're now investigating the possibility of implementing a Unit of Work pattern that encompasses our collection of Contexts during a request. There are some great articles about if you google it, but for us, alas, the time it would take to implement outweighs the potential benefit.

On the side, I'm now investigating the complexity of moving to a combined SOA/Unit of Work approach, but again, it's one of those things hindsight slaps you with after having built up an enterprise sized application without the knowledge.

I'm keen to hear other peoples views on the subject.

Smudge202
  • 4,508
  • 2
  • 23
  • 43
  • Thanks. I had figured that letting the GC do it 'at some point' wouldn't be good under heavy load and it would be better to be deterministic, but I'll be the first to admit I don't know much about that area. I wouldn't do a GC.Collect though, see [this](http://stackoverflow.com/questions/2482220/attaching-linq-to-sql-datacontext-to-httpcontext-in-business-layer/2491698#2491698) answer for a better solution. I take it you think that caching the contexts is worthwhile then? – sjmeverett Jul 05 '11 at 10:39
  • I think there's a very vaguely drawn line. Simply due to the structure of our application, anything other than a singleton pattern for the contexts (implemented as a factory storing contexts in HttpContext) would have been a nightmate for us - having to ensure entities were loaded on the relevant contexts, ensuring contexts have not been disposed when using deferred loaded properties. We did have an _incident_ whereby we were generating around 15 contexts more than required during each request, possibly similar to not caching the contexts. There was a significant performance hit as a result. – Smudge202 Jul 05 '11 at 10:51
  • Here's an interesting [post](http://stephenwalther.com/blog/archive/2008/08/20/asp-net-mvc-tip-34-dispose-of-your-datacontext-or-don-t.aspx) I just stumbled across that might apply to you. I presume the same applies to EF contexts as well - basically, the SQL connections will all be closed anyway, so don't worry about disposing the context. – sjmeverett Jul 05 '11 at 11:14
  • I hadn't found that post so thank you for the link. Something else to note, when I mentioned the GC disposing our context in _due course_, the analyser showed them being dropped almost immediately after the request finished - particularly obvious when returning large result sets on the context. I can't find why that behaviour exists though - my first thought was that a gen1 collection occurs automatically when the request completes but that didn't really add up. This is definitely one of those things you'll need to run some performance monitoring on to see what works best for you. Good luck! – Smudge202 Jul 05 '11 at 12:04