I have always googled for the IoC container lifetime of DbContext, Unit of Work, and Repositories every time I create practice projects from scratch. I tend to forget what their lifetime should be, perhaps because I don’t know the why behind it.
Good thing I found this peer reviewed resource named “.NET Microservices Architecture for Containerized .NET Applications”, which I am using in one of my trainings in the company I am currently working for, Arcanys.
It says that the DbContext and Unit of Work should have the lifetime of scoped. And it gives the why behind that recommendation:
The
DbContext
object (exposed as anIUnitOfWork
object) should be shared among multiple repositories within the same HTTP request scope. For example, this is true when the operation being executed must deal with multiple aggregates, or simply because you are using multiple repository instances…In order to do that, the instance of the
DbContext
object has to have its service lifetime set toServiceLifetime.Scoped
.
And regarding repositories, it says that it can have the socped or the transient lifetime:
… repository’s lifetime should usually be set as scoped (InstancePerLifetimeScope in Autofac). It could also be transient (InstancePerDependency in Autofac), but your service will be more efficient in regards memory when using the scoped lifetime.
Note that using the singleton lifetime for the repository could cause you serious concurrency problems when your DbContext is set to scoped (InstancePerLifetimeScope) lifetime (the default lifetimes for a DBContext).
I hope brain will not forget this ever…
Since
DbContext
instances contain request-specific data and are not thread-safe, each request should get its ownDbContext
instance……
Letting
ShoppingBasketRepository
have a Singleton Lifestyle would cause DbContext to be kept alive for the application’s lifetime. This is dreadful because that would cause it to be used by multiple requests simultaneously—a horrible prospect. Again: DbContexts are not thread-safe.— Steven van Deursen, The Closure Composition Model
The ProductService class is a stateless service, and therefore thread-safe, so it’s an excellent candidate for the Singleton.
— Mark Seemann, Captive Dependency
the rule of thumb is the inner object should have an equal or longer lifetime than the outer one — akazemis, comment on StackOverflow
Captive Dependency by Mark Seemann
Since then, I’ve thought of the name Captive Dependency, which may not be super-catchy, but at least accurately describes the problem. A longer-lived object (e.g. a Singleton) holds a shorter-lived object captive, past its due release time. Although the shorter-lived object should be released, it’s not, because of a bureaucratic error.
A Captive Dependency is a dependency that’s inadvertently kept alive for too long because its consumer was given a lifetime that exceeds the dependency’s expected lifetime. — from The Closure Composition Model
Simple Injector has built in support for a number of container verifications including lifestyle mismatches (Captive Dependency is a lifestyle mismatch) through its Diagnostic Services.
…
And for completeness we should also mention how to solve the captive dependency problem. From the really awsome SimpleInjector documentation:
Change the lifestyle of the component to a lifestyle that is as short or shorter than that of the dependency.
Change the lifestyle of the dependency to a lifestyle as long or longer than that of the component.
Instead of injecting the dependency, inject a factory for the creation of that dependency and call that factory every time an instance is required.
For the above example you would probably want to introduce a factory for the DbContexts.
— qujck, from the comments section of “Captive Dependency”
Should I Use Entity Framework by Tim Corey
My answer is typically “No”. [But…]
EntityFramework: Yes or No? by Dinis Ferreira
Like everything else, EF has qualities and flaws…
Uncle Bob Martin also talked about ORM’s in his blog posts “Dance you Imps!” and “Classes vs. Data Structures”