why life time of DBContext object is very short - asp.net-core

as per microsoft documentation " A DbContext instance is designed to be used for a single unit-of-work. This means that the lifetime of a DbContext instance is usually very short." what life time i choose scoped,singleton or transient? what problem occured if i use DBcontext object as singleton

When you call
services.AddDbContext<MyContext>(options => { });
The DbContext will be registered as a scoped service. So a new instance will be created for each and every request.
This is the most flexible approach, as it allows you to configure a different ConnectionString, based on the tenant that's associated with eg the HttpContext (for example: a different ConnectionString depending on the HttpContext.Request.Host)

Reusing same instance of DbContext will cause bugs: calling SaveChanges will save ALL tracked objects modified by a different consumers of DbContext.
If you worry about performance you may take a look at DbContext pooling

Related

DryIoc ASP.Net Core 3.1 DbContext store in Scope Container

I am using DryIoc (last release version) for Dependency Injection.
In my application (Asp.net Core 3.1), I am using Entity Framework.
My AppDbContext hinerits DbContext and implements IDisposable
I also use UnitOfWork pattern and the class is disposable.
These two objects are declared as Transient.
I follow the documentation of DryIoc that explains the context with Transient Disposable objects:
https://github.com/dadhi/DryIoc/blob/master/docs/DryIoc.Docs/ReuseAndScopes.md
For my AppDbContext, I resolve this service manually. Same thing for my UnitOfWork. At the end I call Dispose method.
But these two instances are not destroyed and are stored in the Singleton Scope of the DryIoc Container.
I did some tests and use JetBrain dotMemory.
My test is to call 100 times a method
Call controler
open UnitOfWork
create AppDbContext
call database to get my data
close / dispose objects.
At the end, I have 100 times my AppDbContext and my UnitOfWork in the scope of the container:
I tried a lot of combinations of creation of container but each time, it is the same thing:
var container = new Container(rules =>
rules.With(propertiesAndFields: request => request.ServiceType.Name.EndsWith("Controller") ? PropertiesAndFields.Auto(request) : null)
// .WithoutThrowOnRegisteringDisposableTransient()
// .WithTrackingDisposableTransients()
.WithoutThrowIfDependencyHasShorterReuseLifespan())
.WithDependencyInjectionAdapter(services);
Result: memory is growing up fast because of these two kind of objects stored in the scope.
If I comment .WithoutThrowOnRegisteringDisposableTransient(), my code is still working (I thought an exception would be thrown)
I tried also to declare these services as Scoped (for each http request) but it does not work because I don't create scope for each query. (Exception thrown and a scope is automatically opened per each web request by Asp .Net Core framework).
Maybe I need to dispose scope at the end of each request?
How could I force destruction of objects?
Thanks to the author of the lib, I found solution:
https://github.com/dadhi/DryIoc/issues/261

Create new DbContext dynamically when using ASP.Net Core dependency injection

I've configured my DbContext with services.AddDbContext() in the Startup class and constructor injection in my controllers works very well.
By default it's a scoped service, but I have one place in the app where I want to update a single property of an entity in a separate scope of work. So I need to create a new DbContext in the controller, but I'm not sure how. I want it to be created by the DI so I don't have to manually call the constructor and provide all the options needed. Is there a way to do that? Maybe there's a way to get the db context options from the DI? Then I could construct the DbContext easily.
The normal method of injecting a DbContext into your Controller works fine, as long as you are doing a small amount of work during an HTTP request. However, you might want to create a DbContext for a long-running a operation that queries/modifies a lot of records (causing SaveChangesAsync() to get bogged down because DbContext.ChangeTracker is tracking a lot of objects). In that case, you can create a scoped DbContext for each operation ("unit of work"). Here is an example ASP.NET Core Controller method:
/// <summary>
/// An endpoint that processes a batch of records.
/// </summary>
/// <param name="provider">The service provider to create scoped DbContexts.
/// This is injected by DI per the FromServices attribute.</param>
/// <param name="records">The batch of records.</param>
public async Task<IActionResult> PostRecords(
[FromServices] IServiceProvider provider,
Record[] records)
{
// The service scope factory is used to create a scope per iteration
var serviceScopeFactory =
provider.GetRequiredService<IServiceScopeFactory>();
foreach (var record in records)
{
// At the end of the using block, scope.Dispose() will be called,
// releasing the DbContext so it can be disposed/reset.
using (var scope = serviceScopeFactory.CreateScope())
{
var context = scope.ServiceProvider.GetService<MainDbContext>();
// Query and modify database records as needed
await context.SaveChangesAsync();
}
}
return Ok();
}
Also, I would recommend switching from AddDbContext() to AddDbContextPool() in Startup.cs to avoid creating/destroying DbContext objects for each request. The DbContextPool will reset the DbContext objects to a clean state after they go out of scope. (In case you were interested, DbContextPool calls DbContext.ResetState() and DbContext.Resurrect(), but I wouldn't recommend calling those directly from your code, as they will probably change in future releases.)
https://github.com/aspnet/EntityFrameworkCore/blob/v2.2.1/src/EFCore/Internal/DbContextPool.cs#L157
Finally, be aware that there are a few pitfalls of creating multiple DbContexts:
Using a large number of DbContexts in parallel may cause the database server to run out of active connections, since many EF database providers open a database connection per DbContext. (Requesting and releasing pooled DbContext objects in a loop should be fine.)
There may be more efficient ways to do the same thing. On my project, I tested and found that running a single "upsert" on a single DbContext was significantly faster than running a SELECT and INSERT/UPDATE on a separate DbContext for each record. There are a number of implementations of upsert for EF Core. For example, here are two that I have used:
FlexLabs.Upsert: https://github.com/artiomchi/FlexLabs.Upsert
EF Extensions BulkMerge: https://entityframework-extensions.net/bulk-merge
One option is to inject IDbContextFactory into your comtroller to create contexts within using blocks.
https://msdn.microsoft.com/en-us/library/hh506876(v=vs.113).aspx

Having more than one entity context

Let's say I've extended identity framework dbContext to build my own, and I've our authenticated controller who get injected with the dbContext and fetch an entity related with the current ApplicationUser, entity framework will relate the two entities leading to a server error because of circular references.
We don't want to serialize circular references.
So we create a new dbContext in the method who istantiate a new dbcontext and query the unrelated entities, this will work. But this is not testable, we don't want our controller to strictly depends on the dbContext, we want it to be injected.
So we add a second parameter, in the constructor, unfortunately this will make the system inject the same dbContext twice, not so useful.
We tried to create a class fakeDbContext who inherit from dbContext and add it services and use it, but now we got two dbcontext, who can potentially generate migrations and configurations and errors...
Which is the right way of doing this in the new MVC6 ?
Edit...
I found out that if my controller require an IEnumerable<dbContext> i get all the object registered as service of that type, so just doubling the part in startup.cs where we add the dbContext in the service registration area i get two of them...
The drawback here is that i don't know wich one is the virgin one, it looks like it goes in order of registration, but i have no clue, if this will change.
Edit 2 ...
I've created a TransientDbService class who have just a factory method taking the IserviceProvider, it use it to get the options to construct the dbContext, and then expose it. I've registered it as transient, then in the controller i require this service type.
the drawback here is if i'll ever need a third dbContext i should write more code, more code means errors and maintaning it.
Edit 3 ...
Not having two dbContext at all. The following setting allow me to have no relationships valorized.
Database.ChangeTracker.QueryTrackingBehavior = Microsoft.Data.Entity.QueryTrackingBehavior.NoTracking;
The drawback here is that i can't use my model graph, making everything more complex...
Edit 4 ...
https://github.com/aspnet/DependencyInjection/issues/352
You are right to think that no tracking queries will help in some cases, but other times you'll need to have more than one instance of the DbContext created.
You normally use the AddDbContext<TContext>() method in startup to make sure an instance of your context type is created per request and the right DbContextOptions and service provider get set on it. When you need to deviate from this pattern you have a few options, e.g.:
Include a constructor in your derived DbContext class that takes an IServiceProvider and passes it to the base constructor. Make sure your controller takes IServiceProvider. Once you do this you should be able to create DbContext manually with something like this:
using(var context1 = new MyDbContext(serviceProvider),
var context2 = new MyDbContext(serviceProvider))
{ ...
To avoid having to change the constructor signatures on your derived DbContext type you can take advantage of the DbContextActivator class (it is our Internal namespace), e.g.:
using(var context1 = DbContextActivator.CreateInstance<MyDbContext>(serviceProvider),
var context2 = DbContextActivator.CreateInstance<MyDbContext>(serviceProvider)
{...
Note: If you are still using AddDbContext<MyDbContext>(options => ...) in startup it should pull those options automatically from the service provider. But you can also choose to either include the DbContextOptions as a parameter in the constructor or override the OnConfiguring() method for that.
I am giving you examples that create two separate DbContexts in a using block, but you should also be able to mix those with the regular "per-request" DbContext you would get injected in the controller's constructor.
Besides these options currently available I have created a new issue to track other possible improvements on how to create multiple instance of the same DbContext type in the same request:
https://github.com/aspnet/EntityFramework/issues/4441

NHibernate Session gets disposed off on each wcf service method call

I am using Wcf in Sharp Architecture. I have configured my project following northwind sample using WcfSessionStorage etc. I have a method in the wcf service that gets a list of business object using Repository<>.GetAll(). I am testing the service method using WcfTestClient. When the method is called the very first time, everything works fine. However on the subsequent call, I get the following exception on the Repository<>.GetAll() method
[System.ObjectDisposedException]
Session is closed!
Object name: 'ISession'
It seems like the NHibernate session gets disposed after each call. I have got around this problem by decorating my service with the following attribute
[ServiceBehavior( InstanceContextMode = InstanceContextMode.PerCall )]
public class WcfService : IWcfService
{
}
However this means, an instance of the service will be created on each call that in turn will create a new nhibernate session etc. In my scenario there is no need of creating a new service instance per call and I think its an expensive process and not the right solution. I would like to know what is the best practice in my scenario and how to get this thing work with creating a new service instace per call.
Thanks
Nabeel
The easiest way is to create a new instance every time and it's not an expensive process, because creating a new object in .NET is like 0.00000000000000001 second (I read that on Ayande's blog or somewhere).
I use Autofac DI in my projects and I usually make ISession as container scoped (one per request). And then every class that uses (directly or indirectly) ISession has to be container scoped or lower (factory scoped == every class usage get's a new instance). If a class that uses ISession is higer scoped (session scoped == singleton) you'll run into problems that you currently have.
If your service is singleton service:
At first run the service is created, this service uses ISession, which should be container scoped, and it is on the first run.
The next request to service (service is now created) has still a reference to created ISession (which was closed on previous end request), so now it's closed.
I don't recomend using the same ISession that you'll open/close (it's not recomended in the NHibernate documentation), just use container scoped (I do and I don't have any performance issues), or you should create ISession manually in every method in your service like:
using(ISession s = ISessionFactory.OpenSession())
using(ITransaction t = .....)
....
But that isn't nice at all...
Please take a look at my answer to my own similar question: WCF/S#arpArch: underlying ISession is closed after the first call within a request.
#dmonlord is right that the creation of additional session instances within the same request is very cheap in this case.

Managing NHibernate ISession with Autofac

Does anyone have any tips or best practices regarding how Autofac can help manage the NHibernate ISession Instance (in the case of an ASP.NET MVC application)?
I'm not overly familiar with how NHibernate sessions should be handled. That said, Autofac have excellent instance lifetime handling (scoping and deterministic disposal). Some related resources are this article and this question. Since you're in ASP.Net MVC land make sure you also look into the MVC integration stuff.
To illustrate the point, here's a quick sample on how you can use Autofac factory delegates and the Owned generic to get full control over instance lifetime:
public class SomeController
{
private readonly Func<Owned<ISession>> _sessionFactory;
public SomeController(Func<Owned<ISession>> sessionFactory)
{
_sessionFactory = sessionFactory;
}
public void DoSomeWork()
{
using (var session = _sessionFactory())
{
var transaction = session.Value.BeginTransaction();
....
}
}
}
The container setup to get this to work is quite simple. Notice that we don't have to do anything to get the Func<> and Owned<> types, these are made available automatically by Autofac:
builder.Register(c => cfg.BuildSessionFactory())
.As<ISessionFactory>()
.SingleInstance();
builder.Register(c => c.Resolve<ISessionFactory>().OpenSession());
Update: my reasoning here is that, according to this NHibernate tutorial, the lifetime of the session instance should be that of the "unit of work". Thus we need some way of controlling both when the session instance is created and when the session is disposed.
With Autofac we get this control by requesting a Func<> instead of the type directly. Not using Func<> would require that the session instance be created upfront before the controller instance is created.
Next, the default in Autofac is that instances have the lifetime of their container. Since we know that we need the power to dispose this instance as soon as the unit of work is done, we request an Owned instance. Disposing the owned instance will in this case immediately dispose the underlying session.
Edit: Sounds like Autofac and probably other containers can scope the lifetime correctly. If that's the case, go for it.
It isn't a good idea to use your IoC container to manage sessions directly. The lifetime of your session should correspond to your unit of work (transaction boundary). In the case of a web application, that should almost certainly be the lifetime of a web request.
The most common way to achieve this is with an HttpModule that both creates your session and starts your transaction when a request begins, then commits when the request has finished. I would have the HttpModule register the session in the HttpContext.Items collection.
In your IoC container, you could register something like HttpContextSessionLocator against ISessionLocator.
I should mention that your generic error handling should locate the current session and roll back the transaction automatically, or you could end up committing half a unit of work.