Why is my ApplicationDbContext getting disposed when I dispose of UserManager/RoleManager in my database initializer Seed()? - entity-framework

I'm playing with MVC 5, and I've created a website that uses ASP.NET Identity. I followed the steps in this blog post on MSDN to create a user and a role in the Seed method for my database initializer.
However, I noticed that the UserManager and RoleManager used in that code both implement IDisposable, so I changed the code slightly, to look something like this (and thus dispose them once I've finished with them):
protected override void Seed(ApplicationDbContext context)
{
using (var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context)))
using (var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context)))
{
EnsureRoleCreated(roleManager, Roles.Administrator);
const string AdministratorUserName = "admin";
const string DefaultAdminPassword = "password";
var user = EnsureUserCreated(userManager, AdministratorUserName, DefaultAdminPassword);
EnsureUserIsInRole(userManager, user, Roles.Administrator);
}
base.Seed(context);
}
Now, when my controller actions attempt to access the DB, I get an exception saying that my DbContext has been disposed. (I new up a DbContext instance in the constructor for my controller).
[If I remove those using() statements and thus do not dispose the UserManager and RoleManager, then the problem goes away, so it's definitely those using() statements that are making the difference.]
This seems very odd to me. If the "correct" way to deal with this is to not explicitly dispose the UserManager and RoleManager, then surely they will still be disposed eventually when the garbage collector kicks in. Since this is unpredictable and could happen at any time, does this not mean that I have a ticking time-bomb in my application?
It seems to me that since I created the DbContext, I should be responsible for disposing of it. Why the heck are UserManager and/or RoleManager disposing of something they did not create?

It is the RoleStore that disposes the DbContext even if it did not create it.
The UserStore has a DisposeContext bool property that controls if the context should be disposed or not. The DisposeContext is false if you use the constructor that takes a DbContext as input.
This seems to have been fixed in the nightly builds. Here the RoleStore also have the DisposeContext property and seems to work as expected.

Related

Blazor Server App and IDbContextFactory not disposing

I have a blazor server application that needs to indirectly connect to a EF core DB context.
None of the blazor components will directly inject an instance of the dbcontext. I am using mediator which will handle all business operations.
The documentation that I have seen so far recommends using IDbContextFactory. I gave it a try but I am not seeing the DbContext created by the factory being disposed. The services that inject IDbContext are not disposed on page changes nor at any other time.
public class QueryHandler : IQueryHandler<Query, Entity>, IDisposable
{
private readonly DbContext dbContext;
public QueryHandler(IDbContextFactory factory)
{
dbContext = factory.CreateDbContext();
}
public Task Handle(Query query)
{
/// do whatever needs to be done.
}
public void Dispose()
{
dbContext.Dispose(); // <-- Dispose never gets called.
}
}
Am I missing something?
The purpose of using a DbContextFactory is to have a DbContext per method.
Exactly because Blazor doesn't offer useful Scopes to handle this.
public class QueryHandler : IQueryHandler<Query, Entity> //, IDisposable
{
...
public QueryHandler(IDbContextFactory factory)
{
_factory = factory;
}
public Task Handle(Query query)
{
using var dbContext = _factory.CreateDbContext();
/// do whatever needs to be done.
}
//public void Dispose() { }
}
This way the DI container and Factory only manage the configuration of the DbContext. Lifecycle management of the DbContext is manual. The Factory is a simple Transient object, is owns no resources.
Manual management usually is with a using statement or using declaration but Blazor also offers an OwningComponentBase. I don't see it being used much.
In Server the DI container exists for the lifetime of the Hub Session and in WASM the lifetime of the Application. Any service objects created within the container, whether Scoped or Transient, implementing IDisposable, are not Disposed until the DI container itself is destroyed. You don't make clear the scope of QueryHandler, but if it's transient that's bad news. You will keep creating new DBContexts without the old ones being disposed.
The purpose of the DbContextFactory is to create unit of work DbContext instances that are used and then quickly disposed correctly. You need to take this approach because DB access will almost certainly be asynchronous. Use a single context and you will quickly hit the situation where you are awaiting one query to complete while trying to use the same context in another operation.
Henk's answer shows you how to use and consume factory created contexts.

The operation cannot be completed because the DbContext has been disposed in entity

private void FunctionA(int t)
{
var c=Context.Entities.TableStudent.Where(x => x.StudentBranch ==t).ToList();
using(var db=Context.Entities)
{
foreach (var q in c)
{
var cb=Context.Entities.Student...
.
.
.
}
DbContext.Entities.SaveChanges();
}
}
c.ForEach(a => a.Situation=true);
DbContext.Entities.SaveChanges();
}
I take DbContext.Entities.SaveChanges(); line give error.This error is
The operation cannot be completed because the DbContext has been disposed.
How can I do it this error.
.
Ok, first up, continue reading/learning about IDisposable, using() blocks, and also naming conventions. You aren't doing yourself any favors by making your code more difficult to understand trying to remember what "a", "c", etc. are, just to save a few seconds typing out a meaningful name.
I'm rather surprised that the code you pasted actually would compile, but without knowing what "Context" is vs. "DbContext" (namespaces, static classes??)...
You're going to have a class which extends EF's DbContext, I'm going to call it "MyContext".. I.e.
public class MyContext : DbContext
{
}
Inside of this class you'll have DbSets declared, and likely an overridden method OnModelCreating() to handle any non-trivial configuration for your entities.
public class MyContext : DbContext
{
public DbSet<TableStudent> Students{ get; set; }
}
This class should never be marked as "static".
Then, with your code to manipulate students, related entities and/or other entities where you have DbSets in the DbContext, you will want to scope the lifespan of a DbContext and ensure that all operations against those entities happens within that lifespan. This lifespan is bounded by a using() block. Once the code leaves the using block, the DbContext is disposed. This means any lazy load references made by entities will not work.
using (var myContext = new MyContext())
{
var students= myContext.Students.Where(x => x.StudentBranch == studentBranch).ToList();
foreach (var student in students)
{
// .. logic...
student.Situation = true;
}
myContext.SaveChanges();
}
// After this point, it is unwise/unsafe to "use" any reference to students.
Do what you need to do within the scope of the using block. If you need to pass student data outside, such as to return from a method call, copy the values over to a plain 'ol C# object (ViewModel or DTO) and return that. Accessing Entities outside of the DbContext scope will result in errors because the context that the student was loaded under has been disposed. Even in cases where the scope is kept alive (such as using a Static context [bad!] or scoping the context to the web request with an IoC container, you may avoid errors, but introduce unintended performance problems due to lazy loading.
SaveChanges is something that typically only needs to ever be called once within a lifetime scope of a DbContext. When set up to know the relationships between entities, EF will manage associating things like Foreign Keys between entities, even new entities that you create. One common panic point people reach is a chicken & egg scenario where I want to create an entity with children, but the children need the parent ID which won't exist until SaveChanges gets called. As long as the parent and child relationship is mapped properly, EF will resolve this automatically when SaveChanges is called provided the children were added to the parent's children collection. SaveChanges applies to the whole set of operations against entities the DbContext knows about (and their relations) so it's not applied at an entity by entity basis.
This should hopefully get you started on how to incorporate Entity Framework and working with it's disposable nature. DbContexts are designed to be relatively short-lived, constructed and disposed as needed. Normally these will be scoped to live as long as a unit of work, being a web request / action, or similar. Longer-lived DbContexts will result in performance/resource issues due to their tracking and caching nature. (Plus issues when attempting to scope SaveChanges calls, discarding changes, etc.)

Entity Framework + Autofac - Random errors on save

Using autofac as my IoC framework.
I'd like to be able to set up my DbContext instance in my application's startup.
In my ASP.NET MVC 3 project, I register DbContext instance in Global.asax (PerLifetimeScope). But when I fire up my site on multiple browsers (or multiple tabs) at once, sometimes I get Object reference not set to an instance of an object. or New transaction is not allowed because there are other threads running in the session when I try to save changes back to database. Also I get
ExecuteReader requires an open and available Connection. The connection's current state: Broken. sometimes when I want to read data from database.
the errors seem to pop up randomly and I suspect it has something to do with my context's lifetime scope. here's my DbContext's overriden SaveChange method.
public class MyContext : DbContext
{
public override int SaveChanges()
{
var result = base.SaveChanges(); // Exception here
}
}
Here's how I register my context:
builder.Register(c => new MyContext("SomeConnectionString"))
.InstancePerLifetimeScope();
If I just have one open tab of my site in the browser everything works ok.
Also, It's worth mentioning I have CRUD operations with db every 5-10 seconds in my website by calling a controller method using Ajax.
StackTrace for New transaction is not allowed because there are other threads running in the session:
at System.Data.EntityClient.EntityConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.EntityClient.EntityConnection.BeginTransaction()
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at MyProject.Data.MyContext.SaveChanges() in D:\Test.cs
StackTrace for Object reference not set to an instance of an object.:
at System.Data.Objects.ObjectStateManager.DetectConflicts(IList`1 entries)
at System.Data.Objects.ObjectStateManager.DetectChanges()
at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force)
at System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate)
at System.Data.Entity.Internal.InternalContext.GetStateEntries()
at System.Data.Entity.Infrastructure.DbChangeTracker.Entries()
at System.Data.Entity.DbContext.GetValidationErrors()
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at MyProject.Data.MyContext.SaveChanges() in D:\Test.cs at
Registration of MyContext looks ok. Is it possible that some other service that takes a MyContext is registered as a singleton and being shared across threads?
I had the same issue, sporadic errors related to the DbContext while using Autofac to resolve the DbContext.
{System.Data.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.
etc.
{System.NullReferenceException: Object reference not set to an instance of an object.
at System.Data.Objects.ObjectStateManager.DetectConflicts(IList`1 entries)
etc.
I found a class resembling the following in my code. The dependency resolution was occurring within a static method inside of the singleton. The object being resolved had a dependency on the DbContext. I haven't had any additional issues after I found a way to restructure this class so that it was no longer a singleton.
Perhaps you have a similar situation? Another thing to try might be to make your DbContext InstancePerHttpRequest. That could help identify whether this is the issue.
public class Singleton
{
private static Singleton _instance = new Singleton();
private Singleton()
{
}
public static void DoSomething<TSource>(TSource source) where TSource : ISource
{
var items = DependencyResolver.Current.Resolve<IEnumerable<IDbContextConsumer<TSource>>>();
foreach (var item in items)
{
item.Execute(source);
}
}
}

No need to dispose DataContext/ObjectContext in EF?

Albahari writes in "c# 4.0 in a nutshell":
>
Although DataContext/ObjectContext implement IDisposable, you can (in general)
get away without disposing instances. Disposing forces the context’s connection
to dispose—but this is usually unnecessary because L2S and EF close connections
automatically whenever you finish retrieving results from a query
<<
This feels wrong and FxCop also complains if you are not diposing something that is IDisposable.
I have the following repository code:
public abstract class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{ ...
public void Add(TEntity entity)
{
using (var dbContext = this.UnityContainer.Resolve<DbContext>())
{
dbContext.Set<TEntity>().Add(entity);
dbContext.SaveChanges();
}
}
...
public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> expression)
{
using (var dbContext = this.UnityContainer.Resolve<DbContext>())
{
return dbContext.Set<TEntity>().Where(expression).ToList().AsEnumerable();
}
}
...
Note: I do not return IQueryable - lazy loading should not play a role.
Resolve DbContext is configured as PerResolveLifetimeManager.
Is this approach OK or do I need to reconsider this based on Albaharis description?
You should always call dispose if class exposes it. The statement claims that EF and L2S close connection whenever they finish operation - as I know the statement is correct but in the same time ADO.NET team also closes connection in Dispose method so perhaps there are situations when connection is not closed.
I'm working on EF 4.0 ObjectContext (yeah, I know...). I ended up looking at the code in DotPeek, and the dispose just nulls the reference to the connection and a few other things in the ObjectContext class.
When a connection is created (also found through DotPeek) it returns the existing instance. If the connection string is changed, it'll update the connection string for all instances.
That was my take on it at least. Need to look deeper but at first glance, it seems that you can get away with it.

ObjectDisposedException thrown everytime a "User" (membership) object is updated

I am using asp.net mvc 3, entity framework with structure map for IoC.
I have my own custom membership provider.
I had the same kind of problem when I was injecting the dbcontext object and the membership instances using StructureMap so removed this for my UserRepository.
The UserRepository now has a DBContext property which is initialised in the constructor.
Everytime a new user is created/updated (the method doing this is wrapping the dbcontext object in using statement), the next time the dbcontext is referenced I get ObjectDisposedException thrown.
I don't understand what I am doing wrong. Obviously, the membership provider class isn't instantiating the userRepository object everytime it needs it and when a user is updated, the context is disposed because of the using statement. But I thought this was standard practice?
Any help is greatly appreciated.
EDITED:
There is no complex code really. The set up is:
CustomMembershipProvider overrides the standard Membership provider (config file has got the details).
CustomMembershipProvider uses IUserService object that uses IUserRepository which is implemented by UserRepository that has the DBContext private object at class level.
In the UserRepository, I've got:
public void UpdateUser(User user)
{
using(_db)
{
... code to indicate that the user state has changed
_db.SaveChanges();
}
}
Once this code is run, the request is complete. But when another request is made to retrive role information or read the user from the database (in the UserRepository class), I get the ObjectDisposedException thrown. At this point nothing related to User Or Role works because they use the same UserRepository class whose _db variable has been disposed by UpdateUser.
I initially had StructureMap resolve the DBContext object, the customMembership object etc but have had to since remove it from StructureMap's mapping.
Everytime a new user is
created/updated (the method doing this
is wrapping the dbcontext object in
using statement), the next time the
dbcontext is referenced I get
ObjectDisposedException thrown.
DbContext is a disposable resource(Which implements IDisposable). So when you wrap it in a using block the context is disposed when the control flow goes out of the using block.
using(myContext)
{
//do stuff
}
//try to access myContext after the using block throw ObjectDisposedException
You have to re-design how you use the DbContext and when you are going to dispose it.