DbContextScope icon indicating copy to clipboard operation
DbContextScope copied to clipboard

Need way to disable disposing of DbContext when root DbContextScope is disposed

Open riley-van-hengstum opened this issue 7 years ago • 3 comments

The way this library works now is that the DbContext instances are disposed when the root DbContextScope is disposed.

I'm using this library in an OData Web Api project. The behaviour of disposing DbContext instances is causing problems with the OData pipeline because OData expects the DbContext to be open until very late in the Web Api pipeline. The only way of keeping the DbContext open is to create the DbContextScope very early in the process in the Owin middleware, but I didn't want to do that because I want to have a readonly or readwrite scope depending on the requested controller action, and this is not yet known at the Owin stage.

So I had to resort to trickery to keep the DbContext from being disposed right away, which was to override the Dispose(bool disposing) method of the DbContext and add another ManualDispose() method to dispose of the DbContext at a later time.

It would be nice if it were possible to create a DbContextScope with the option to disable auto disposing of the DbContext instances.

Or does someone have another suggestion to tackle this issue?

riley-van-hengstum avatar May 09 '17 09:05 riley-van-hengstum

Can you just not dispose the DbContextScope?

crush83 avatar Oct 25 '17 02:10 crush83

Jaap-van-Hengstum, please, share your decision, if your figured it out. I'm really on the same page with about this question. I play with .NET Core and native DI for my Web API. Tried many approches with DbContextScope , IAmbientContextLocator and their lifetimes. As I understood correctly, DbContextScope should be Transient and AmbientContextLocator - Singleton. But the problem exactly the same - DbContextScope kills DbContext everytime.

rock-walker avatar Dec 19 '17 20:12 rock-walker

In short words, the answer is: register your DbContext as Transient lifetime.

And ... the long story: In .NET Core 1.1 you register your DbContexts by default in Scoped lifetime, like this: services.AddDbContext<AttendeeContext>(options => options.UseSqlServer(connectionString)

So, how DbContextScope does his job (as long, as I debugged sources):

  1. in each new scope, (like it usually recommends: using (var dbScope = _factory.Create()) { ... } ) the new collection of DbContexts initialized - not previously initialized DbContexts in the current scope of whole web request.
  2. when the dbScope code block ends, using statement calls Dispose for your DbContextScope and that means exact disposing of all your existing collection of DbContexts.
  3. What does it mean for lifetime of DbContext in scope of lifetime of whole Web request? -- it means, that you manually have killed DbContext somewhere in the middle of living your Web request, and DbContext becomes unavailable for next calls inside still alive Web Request.

The solution is to allow your serviceProvider to recreate DbContext for each request during Scoped lifetime of your Web request: services.AddDbContext<AttendeeContext>(options => options.UseSqlServer(connectionString, ServiceLifeTime.Transient) And by the way, I also registered IDbContextScopeFactory as Singleton lifetime.

rock-walker avatar Dec 21 '17 21:12 rock-walker