Singleton Scope for EF's DbContext - c#

so I am currently working on an ASP.NET MVC web application that uses Entity Framework, I'm also using Ninject for Dependency Injection.
So basically, at the moment, this is how I register my DbContext and Services with Ninject.
kernel.Bind<DbContext>().To<MyApplicationContext>().InSingletonScope();
kernel.Bind<IAccountService>().To<AccountService>().InSingletonScope();
kernel.Bind<IRegionService>().To<RegionService>().InSingletonScope();
kernel.Bind<IRoleService>().To<RoleService>().InSingletonScope();
I register them with InSingletonScope, which means that they will only be created once and used throughout the lifetime of the application (at least how I understand it).
Controllers:
private IAccountService _accountService;
public MemberController(IAccountService accountService)
{
_accountService = accountService;
}
However, I have a deep feeling that this singleton scope will cause problem in my web application especially for the Entity Framework's context, due to it being singleton.
I am already facing a minor issue due to this, if I manually update the database using SQL Management Studio, the data in my web application's Entity Framework wouldn't update until I restart the application (seems to be some caching mechanism in EF).
--
However, if I remove the InSingletonScope, I will randomly get errors from EF saying that:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
I understand why this happens because the DbContext initialized by AccountService could be different from say, RegionService. But I have no idea how I can resolve this.
My understanding of Dependency Injection is still very limited, so can anybody please advice?
--
EDIT: I've tried changing to InRequestScope for all the injections, but I'm still getting
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
When trying to insert a new entity with related object (foreign key) from another service in my application. That means they are still using a different DbContext, what is happening?!
FINAL EDIT: Ok I've found the problem, it was my caching mechanism that was caching a previous request, causing the relationship issue on all subsequent request.

The lifetime of some services including DbContext can be configured this way:
services.AddDbContext<ApplicationDbContext>(
options => { options.UseSqlServer("YourConnectionString"); },
ServiceLifetime.Singleton);
REF

Singleton-scope is a very bad idea for your context. Request-scope is what you should be using, as it's essentially a singleton for the life of the request.
As to why you're getting errors when using request-scope, I can't say for sure. Assuming that the entities you're utilizing all originate from the same context type, and that you're properly injecting the context everywhere it's needed, there should never be multiple context instances in play.
EDIT
After re-reading your question, it sounds as if your services are actually initializing the context in their constructors or something. If that's the case, that's your problem. You context should be injected into your services, i.e.:
public class AccountService : IAccountService
{
protected readonly DbContext context;
public AccountService(DbContext context)
{
this.context = context;
}
...
}
Then, Ninject will properly inject the request-scoped instance of MyApplicationContext when newing up any of the services.

Dan, you are creating a bottleneck when you scope a single DBContext for the entire application. Underneath the hood, Entity Framework will handle how many objects you need rather efficiently. If you go deeper into internals, the actual objects contacting the database do the same thing. So your attempt to optimize by making a singleton may actually be creating a very big problem.

I've finally managed to resolve this issue by using InRequestScope instead of InSingletonScope.
Initially, I was still facing the same problem after changing to InRequestScope because of my existing caching mechanism on my services layer.
Thus, all subsequent requests were using the initially-cached entity object, that was why I was getting multiple instances error from EF.
--
If you are still facing the
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
error after changing to InRequestScope, make sure your entities are not somehow cached or stored for subsequent HTTP requests uses.

Related

Sharing/Extending a DbContext from an MVC .NET Core application to a (Razor) class library

I have a web application with its own dbcontext (context1), and I've a Razor class library with another dbcontext (context2). Ideally I should have a single db context...
The problem i have is when some tables "overlap", e.g. context1 contains entity companies, and context2 contains entity users, yet there mayb be a relationship between companies and users.
Is there a way i can ditch context2 from my CL and somehow inject context1 into my class library?
Or perhaps there is a way i can inherit context2 to context1?
Alternatively, if i keep the two contexts, can i keep the from "overlapping", e.g create a view to allow navigation properites between the two contexts? (just thinking out loud now)
Any advice is much appreciated.
Thanks
Whether you have one context definition or two isn't really the issue, it will be how any instance of a DbContext is scoped and whether a single reference can be shared across the two blocks of code.
For instance if I have some code in an MVC project that is doing something like:
using (var context = new AppContext())
{
var myEntity = context.Entities.Single(x => x.EntityId = entityId);
SomeService.DoSomething(myEntity);
}
and a service library doing something like:
public void DoSomething(AppEntity someEntity)
{
using(var context = new AppContext())
{
someEntity.Status = "DidSomething";
context.Attach(someEntity);
context.Entity(someEntity).State = EntityState.Modified;
context.SaveChanges();
}
}
or the like, then you're probably shaping up for a world of discomfort tracking down stale state related issues. Both blocks of code can be referring to the same DbContext type but different DbContext instances which means that the controller's DbContext reference may not reflect, or be tracking entities that the other library context had committed.
As a general rule, an entity should not leave the scope of the DbContext instance that spawned it. Any entity that does should be considered detached, but if it is not explicitly detached from a DbContext instance, this can lead to errors down the road depending on how long-lived the DbContext that spawned it is. If one assembly references the second assembly then you can use Dependency Injection and an IoC container to manage a lifetime scope of a single DbContext instance across calls, or you can use a Unit of Work provider to provision a DbContext and manage the lifetime of that DbContext. This way, when your library is referenced by MVC, it shares a DbContext instance when called, but if called via another means, it resolves a suitable DbContext instance for entities received from that scenario.
For larger systems it can be prudent to use separate DbContext definitions and simplified entity definitions. Smaller, simpler, short-lived DbContexts operate more efficiently when querying/tracking entities. For services that may get called frequently to operate against data, it can be far better to have a simplified entity against a smaller DbContext. Fetch the entity, inspect, modify, and commit rather than trying to attach, modify, and commit using a full-size entity on a full size DbContext instance. Models like this would use minimum-sized payloads (DTOs) rather than entities as payloads. Callers would receive an indication that their scoped entities should be refreshed or not.

How should I manage DbContext Lifetime in MVC Core?

From the Documentation
Entity Framework contexts should be added to the services container
using the Scoped lifetime. This is taken care of automatically if you
use the helper methods as shown above. Repositories that will make use
of Entity Framework should use the same lifetime.
I always thought, that I should create a new Context for every single unit of work I have to process. This let me think, if I have a ServiceA and ServiceB, which are applying different actions on the DbContext that they should get a different Instance of DbContext.
The documentation reads as following:
Transient objects are always different; a new instance is provided to every controller and every service.
Scoped objects are the same within a request, but different across different request
Going back to ServiceA and ServiceB, it sounds to me, Transient is more suitable.
I have researched, that the Context should only saved once per HttpRequest, but I really do not understand how this does work.
Especially if we take a look at one Service:
using (var transaction = dbContext.Database.BeginTransaction())
{
//Create some entity
var someEntity = new SomeEntity();
dbContext.SomeEntity.Add(someEntity);
//Save in order to get the the id of the entity
dbContext.SaveChanges();
//Create related entity
var relatedEntity = new RelatedEntity
{
SomeEntityId = someEntity.Id
};
dbContext.RelatedEntity.Add(relatedEntity)
dbContext.SaveChanges();
transaction.Commit();
}
Here we need to Save the context in order to get the ID of an Entity which is related to another one we just have created.
At the same time another service could update the same context. From what I have read, DbContext is not thread safe.
Should I use Transient in this case? Why does the documentation suggest, I should use Scoped?
Do I miss some important part of the framework?
As others already explained, you should use a scoped dependency for database contexts to make sure it will be properly reused. For concurrency, remember that you can query the database asynchronously too, so you might not need actual threads.
If you do need threads, i.e. background workers, then it’s likely that those will have a different lifetime than the request. As such, those threads should not use dependencies retrieved from the request scope. When the request ends and its dependency scope is being closed, disposable dependencies will be properly disposed. For other threads, this would mean that their dependencies might end up getting disposed although they still need them: Bad idea.
Instead, you should explicitly open a new dependency scope for every thread you create. You can do that by injecting the IServiceScopeFactory and creating a scope using CreateScope. The resulting object will then contain a service provider which you can retrieve your dependencies from. Since this is a seperate scope, scoped dependencies like database contexts will be recreated for the lifetime of this scope.
In order to avoid getting into the service locator pattern, you should consider having one central service your thread executes that brings together all the necessary dependencies. The thread could then do this:
using (var scope = _scopeFactory.CreateScope())
{
var service = scope.ServiceProvider.GetService<BackgroundThreadService>();
service.Run();
}
The BackgroundThreadService and all its dependency can then follow the common dependency injection way of receiving dependencies.
I believe you wouldn't faced with concurrency issues in most cases when you use scoped lifetime. Even in example you posted there is no concurrency problems as services in current request will be called subsequently. I cant even imagine case when you will run 2 or more services in parallel (its possible but not usual) in context of one HTTP request(scope).
Lifetimes its just a way to store your data(to be simple here). Just look on some lifetime managers in popular DI frameworks, all of them works pretty match the same - this is just dictionary like objects that implementing disposable pattern. Using Transient I believe your get object method will always return null so DI will create new instance each time it requested. SingleInstance will store objects in something like static concurrent dictionary so container will create instance only once and then receive existing one.
Scoped is usually mean scope object is used to store created objects. In asp net pipeline it usually mean the same as per request (as scope can be passed through the pipeline)
To be short - don't worry just use scoped it is safe and you can call this as per request.
I've tried to be very simple in my explanation, you can always look to the source code to find as match details as you need here https://github.com/aspnet/DependencyInjection

One DbContext per web request... why?

I have been reading a lot of articles explaining how to set up Entity Framework's DbContext so that only one is created and used per HTTP web request using various DI frameworks.
Why is this a good idea in the first place? What advantages do you gain by using this approach? Are there certain situations where this would be a good idea? Are there things that you can do using this technique that you can't do when instantiating DbContexts per repository method call?
NOTE: This answer talks about the Entity Framework's DbContext, but
it is applicable to any sort of Unit of Work implementation, such as
LINQ to SQL's DataContext, and NHibernate's ISession.
Let start by echoing Ian: Having a single DbContext for the whole application is a Bad Idea. The only situation where this makes sense is when you have a single-threaded application and a database that is solely used by that single application instance. The DbContext is not thread-safe and since the DbContext caches data, it gets stale pretty soon. This will get you in all sorts of trouble when multiple users/applications work on that database simultaneously (which is very common of course). But I expect you already know that and just want to know why not to just inject a new instance (i.e. with a transient lifestyle) of the DbContext into anyone who needs it. (for more information about why a single DbContext -or even on context per thread- is bad, read this answer).
Let me start by saying that registering a DbContext as transient could work, but typically you want to have a single instance of such a unit of work within a certain scope. In a web application, it can be practical to define such a scope on the boundaries of a web request; thus a Per Web Request lifestyle. This allows you to let a whole set of objects operate within the same context. In other words, they operate within the same business transaction.
If you have no goal of having a set of operations operate inside the same context, in that case the transient lifestyle is fine, but there are a few things to watch:
Since every object gets its own instance, every class that changes the state of the system, needs to call _context.SaveChanges() (otherwise changes would get lost). This can complicate your code, and adds a second responsibility to the code (the responsibility of controlling the context), and is a violation of the Single Responsibility Principle.
You need to make sure that entities [loaded and saved by a DbContext] never leave the scope of such a class, because they can't be used in the context instance of another class. This can complicate your code enormously, because when you need those entities, you need to load them again by id, which could also cause performance problems.
Since DbContext implements IDisposable, you probably still want to Dispose all created instances. If you want to do this, you basically have two options. You need to dispose them in the same method right after calling context.SaveChanges(), but in that case the business logic takes ownership of an object it gets passed on from the outside. The second option is to Dispose all created instances on the boundary of the Http Request, but in that case you still need some sort of scoping to let the container know when those instances need to be Disposed.
Another option is to not inject a DbContext at all. Instead, you inject a DbContextFactory that is able to create a new instance (I used to use this approach in the past). This way the business logic controls the context explicitly. If might look like this:
public void SomeOperation()
{
using (var context = this.contextFactory.CreateNew())
{
var entities = this.otherDependency.Operate(
context, "some value");
context.Entities.InsertOnSubmit(entities);
context.SaveChanges();
}
}
The plus side of this is that you manage the life of the DbContext explicitly and it is easy to set this up. It also allows you to use a single context in a certain scope, which has clear advantages, such as running code in a single business transaction, and being able to pass around entities, since they originate from the same DbContext.
The downside is that you will have to pass around the DbContext from method to method (which is termed Method Injection). Note that in a sense this solution is the same as the 'scoped' approach, but now the scope is controlled in the application code itself (and is possibly repeated many times). It is the application that is responsible for creating and disposing the unit of work. Since the DbContext is created after the dependency graph is constructed, Constructor Injection is out of the picture and you need to defer to Method Injection when you need to pass on the context from one class to the other.
Method Injection isn't that bad, but when the business logic gets more complex, and more classes get involved, you will have to pass it from method to method and class to class, which can complicate the code a lot (I've seen this in the past). For a simple application, this approach will do just fine though.
Because of the downsides, this factory approach has for bigger systems, another approach can be useful and that is the one where you let the container or the infrastructure code / Composition Root manage the unit of work. This is the style that your question is about.
By letting the container and/or the infrastructure handle this, your application code is not polluted by having to create, (optionally) commit and Dispose a UoW instance, which keeps the business logic simple and clean (just a Single Responsibility). There are some difficulties with this approach. For instance, where do you Commit and Dispose the instance?
Disposing a unit of work can be done at the end of the web request. Many people however, incorrectly assume that this is also the place to Commit the unit of work. However, at that point in the application, you simply can't determine for sure that the unit of work should actually be committed. e.g. If the business layer code threw an exception that was caught higher up the callstack, you definitely don't want to Commit.
The real solution is again to explicitly manage some sort of scope, but this time do it inside the Composition Root. Abstracting all business logic behind the command / handler pattern, you will be able to write a decorator that can be wrapped around each command handler that allows to do this. Example:
class TransactionalCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
readonly DbContext context;
readonly ICommandHandler<TCommand> decorated;
public TransactionCommandHandlerDecorator(
DbContext context,
ICommandHandler<TCommand> decorated)
{
this.context = context;
this.decorated = decorated;
}
public void Handle(TCommand command)
{
this.decorated.Handle(command);
context.SaveChanges();
}
}
This ensures that you only need to write this infrastructure code once. Any solid DI container allows you to configure such a decorator to be wrapped around all ICommandHandler<T> implementations in a consistent manner.
There are two contradicting recommendations by microsoft and many people use DbContexts in a completely divergent manner.
One recommendation is to "Dispose DbContexts as soon as posible"
because having a DbContext Alive occupies valuable resources like db
connections etc....
The other states that One DbContext per request is highly
reccomended
Those contradict to each other because if your Request is doing a lot of unrelated to the Db stuff , then your DbContext is kept for no reason.
Thus it is waste to keep your DbContext alive while your request is just waiting for random stuff to get done...
So many people who follow rule 1 have their DbContexts inside their "Repository pattern" and create a new Instance per Database Query so X*DbContext per Request
They just get their data and dispose the context ASAP.
This is considered by MANY people an acceptable practice.
While this has the benefits of occupying your db resources for the minimum time it clearly sacrifices all the UnitOfWork and Caching candy EF has to offer.
Keeping alive a single multipurpose instance of DbContext maximizes the benefits of Caching but since DbContext is not thread safe and each Web request runs on it's own thread, a DbContext per Request is the longest you can keep it.
So EF's team recommendation about using 1 Db Context per request it's clearly based on the fact that in a Web Application a UnitOfWork most likely is going to be within one request and that request has one thread. So one DbContext per request is like the ideal benefit of UnitOfWork and Caching.
But in many cases this is not true.
I consider Logging a separate UnitOfWork thus having a new DbContext for Post-Request Logging in async threads is completely acceptable
So Finally it turns down that a DbContext's lifetime is restricted to these two parameters. UnitOfWork and Thread
Not a single answer here actually answers the question. The OP did not ask about a singleton/per-application DbContext design, he asked about a per-(web)request design and what potential benefits could exist.
I'll reference http://mehdi.me/ambient-dbcontext-in-ef6/ as Mehdi is a fantastic resource:
Possible performance gains.
Each DbContext instance maintains a first-level cache of all the entities its loads from the database. Whenever you query an entity by its primary key, the DbContext will first attempt to retrieve it from its first-level cache before defaulting to querying it from the database. Depending on your data query pattern, re-using the same DbContext across multiple sequential business transactions may result in a fewer database queries being made thanks to the DbContext first-level cache.
It enables lazy-loading.
If your services return persistent entities (as opposed to returning view models or other sorts of DTOs) and you'd like to take advantage of lazy-loading on those entities, the lifetime of the DbContext instance from which those entities were retrieved must extend beyond the scope of the business transaction. If the service method disposed the DbContext instance it used before returning, any attempt to lazy-load properties on the returned entities would fail (whether or not using lazy-loading is a good idea is a different debate altogether which we won't get into here). In our web application example, lazy-loading would typically be used in controller action methods on entities returned by a separate service layer. In that case, the DbContext instance that was used by the service method to load these entities would need to remain alive for the duration of the web request (or at the very least until the action method has completed).
Keep in mind there are cons as well. That link contains many other resources to read on the subject.
Just posting this in case someone else stumbles upon this question and doesn't get absorbed in answers that don't actually address the question.
I'm pretty certain it is because the DbContext is not at all thread safe. So sharing the thing is never a good idea.
One thing that's not really addressed in the question or the discussion is the fact that DbContext can't cancel changes. You can submit changes, but you can't clear out the change tree, so if you use a per request context you're out of luck if you need to throw changes away for whatever reason.
Personally I create instances of DbContext when needed - usually attached to business components that have the ability to recreate the context if required. That way I have control over the process, rather than having a single instance forced onto me. I also don't have to create the DbContext at each controller startup regardless of whether it actually gets used. Then if I still want to have per request instances I can create them in the CTOR (via DI or manually) or create them as needed in each controller method. Personally I usually take the latter approach as to avoid creating DbContext instances when they are not actually needed.
It depends from which angle you look at it too. To me the per request instance has never made sense. Does the DbContext really belong into the Http Request? In terms of behavior that's the wrong place. Your business components should be creating your context, not the Http request. Then you can create or throw away your business components as needed and never worry about the lifetime of the context.
I agree with previous opinions. It is good to say, that if you are going to share DbContext in single thread app, you'll need more memory. For example my web application on Azure (one extra small instance) needs another 150 MB of memory and I have about 30 users per hour.
Here is real example image: application have been deployed in 12PM
What I like about it is that it aligns the unit-of-work (as the user sees it - i.e. a page submit) with the unit-of-work in the ORM sense.
Therefore, you can make the entire page submission transactional, which you could not do if you were exposing CRUD methods with each creating a new context.
Another understated reason for not using a singleton DbContext, even in a single threaded single user application, is because of the identity map pattern it uses. It means that every time you retrieve data using query or by id, it will keep the retrieved entity instances in cache. The next time you retrieve the same entity, it will give you the cached instance of the entity, if available, with any modifications you have done in the same session. This is necessary so the SaveChanges method does not end up with multiple different entity instances of the same database record(s); otherwise, the context would have to somehow merge the data from all those entity instances.
The reason that is a problem is a singleton DbContext can become a time bomb that could eventually cache the whole database + the overhead of .NET objects in memory.
There are ways around this behavior by only using Linq queries with the .NoTracking() extension method. Also these days PCs have a lot of RAM. But usually that is not the desired behavior.
Another issue to watch out for with Entity Framework specifically is when using a combination of creating new entities, lazy loading, and then using those new entities (from the same context). If you don't use IDbSet.Create (vs just new), Lazy loading on that entity doesn't work when its retrieved out of the context it was created in. Example:
public class Foo {
public string Id {get; set; }
public string BarId {get; set; }
// lazy loaded relationship to bar
public virtual Bar Bar { get; set;}
}
var foo = new Foo {
Id = "foo id"
BarId = "some existing bar id"
};
dbContext.Set<Foo>().Add(foo);
dbContext.SaveChanges();
// some other code, using the same context
var foo = dbContext.Set<Foo>().Find("foo id");
var barProp = foo.Bar.SomeBarProp; // fails with null reference even though we have BarId set.

asp.net mvc3 Code First (Database Singleton)

I am working on asp.net mvc using code first. I noticed that once i create a new controller, the controller template shows dispose overridden method that just has one job; dispose db variable created at the top of this controller.
I am thinking of changing this to use singleton pattern with my DBContext class.
I tried it and it worked fine. except that i needed sometimes to access database from global.asax. (sometimes) is throws an exception.
Have anyone thought to do the same? Any ideas?
Thank you
personally I would follow a completely different approach, see my answer here: https://stackoverflow.com/a/7474357/559144 I would not use Singleton and would not hardlink MVC which is a UI framework with the DAL (EF in your case).
about not using singleton, let the database handle concurrency; it's one of the things Database servers do the best ;-)
We use EF context as a singleton per http context. I also would not hard link EF with MVC, but you can still be sure that each http context deals with a single EF context instance by using dependency injection (we use Unity).
We also access the context in global asax to do db initialization and seeding for development. Again, you can use a DI container to get an instance of the EF context.
public interface IUnitOfWork : IDisposable
{
int SaveChanges();
}
public class MyEfContext : DbContext, IUnitOfWork
{
// your custom context code
}
Using a singleton-per-http-context lifetime for the IUnitOfWork dependency injection isn't an approach to help deal with concurrency in our case. We do it because when dealing with EF entities, we need to make sure all of the selects / inserts / updates / deletes always happen with the same context instance. EF does not let you attach entities to multiple contexts, and we use singleton per http context for this reason.

Entity Framework 4 ObjectContext GuideLines

I read in a previous article about how to resolve a solution by placing the ObjectContext of my Db in a property within HttpContext.Current.Items["Db"]; This works fantastic, however I have a question. Does this means that every time I use my repository I have to pass the ObjectContext within HttpContext.Current.Items or do I only need to do this when I am creating or updating an entity that has a reference to another entity.
Within my repository classes I have 2 ways of instantiating them, with a ObjectContext and without one in which the ObjectContext is created there within the entity.
You should share one context among all your repositories used in single HTTP request processing. You should also dispose context at the end of request processing. Generally your repository should not be dependent on HttpContext. The best way is to create ObjectContext outside of your repositories and always pass it to their constructor. You can also do that by using some IoC container like Windsor, StructureMap, Ninject or Unity.

Categories

Resources