Cannot access a disposed context instance EF core
Asked Answered
T

3

5

I am developing a CRM by .net core mvc and EF which needs a lot of DB connection to retrieve and update information. From time to time I face this error during debugging, this is a big project with a lot of users I don't know how it will work in real usage!

Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.\r\nObject name: 'XXX'.

before I used this setting in startup.cs:

services.AddDbContext<XXX>
                (option => 
                option.UseSqlServer(Configuration.GetConnectionString("YYY"))
                .ServiceLifetime.Singleton);

that setting was lead to another error occasionally:

System.InvalidOperationException: The instance of entity type 'TblZZZ' cannot be tracked because another instance with the same key value for {'ZZZId'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

so I have changed my setting to:

services.AddDbContext<XXX>
                (option => 
                option.UseSqlServer(Configuration.GetConnectionString("YYY"))
                .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking));

now I am facing the Cannot access a disposed context instance. I don't know what setting can solve my issue.

I m using net5.0

Update: my partial class:

public partial class TblXXX
    {
        private ZZZ context;//context
        public TblXXX(ZZZ _context)
        {
            context = _context;
        }
        public TblXXX() { }
//function for check username
   public bool CheckUsernameExit(string username) {
            var u = context.TblXXX
                .Where(e => e.Username == username)
                .FirstOrDefault();
            return (u != null);
        }
}

in my controller:

  public IActionResult Check(UserModelView user)
        {
            if (ModelState.IsValid)
            {
                var r = _viewModel.tblXXX.CheckUsernameExit(user.tblXXX.Username);
                if (r)
                {
                    toastNotification.AddErrorToastMessage("This email is in use. Enter differernt email.");
                 
                    return View("Create", _viewModel);
                }
            

and this is my ViewModel:

 public class UserModelView
    {
        public TblXXX tblXXX { get; set; }
        public List<TblXXX > tblXXXList { get; set; }
    }
          

this is one of the cases I face the error.

Trifocal answered 27/3, 2021 at 10:57 Comment(10)
Use AddDbContext<XXX> and configure just the connection string is enough, don't try to modify the service lifetime which is Scoped by default (and should always be so). You must have a problem somewhere else, I'm pretty sure about that. So now you don't even know where it could be, we may be all stuck with this.Bant
Don't use Singleton lifetime, use Scoped or even Transient depending on how you are using it in codePede
Possible duplicate: stackoverflow.com/q/66531676/264697Braque
@KingKing it is a very big project but if I want to summarize it when I face this issue become this: I made some partial classes alongside EF generated partial classes. in my classes, I try to do different functions such as some complicated queries and simple ones like an update directly by linq or even SPs. in the controller, if I don't make new objects of my partial class with dbcontext in constructor I faced this error. it seems they need fresh dbcontext always!Trifocal
@KingKing I have updated my question with one example I appreciate it if you have look.Trifocal
@Braque I read that post, so you mean I should make all my db related task async? could please have look at my question again I have updated it.Trifocal
this is a hard-to-detect issue, almost only solvable by you and not by others unless we have a chance to scan through all the code in your projects (but that's impossible partly because of consuming a lot of time). Generally, you get this error when the DbContext somehow is still being used after the request processing ended, it could be a caching issue, some issue with background threading/task ... The general principle is simple but to pinpoint the exact code that causes the issue, you will have to do that yourself, I don't think someone here can help.Bant
thanks for your reply @KingKing, as the role of thumb should I use saveChange function after any single changes to dbContext or I can do it after multiple tasks? like update a entity, add an entity then call saveChange?Trifocal
@PariaShiri SaveChanges is called as a unit-of-work operation which means after you've done everything with the DbContext that should be all succeeded or failed together, you use SaveChanges to persist the data changes.Bant
thank you for the reply @KingKingTrifocal
S
8

In asp.net core the DbContext should be a Scoped service, not a Singleton.

Change this:

services.AddDbContext<XXX>
                (option => 
                option.UseSqlServer(Configuration.GetConnectionString("YYY"))
                .ServiceLifetime.Singleton);

To

services.AddDbContext<XXX>
                (option => 
                option.UseSqlServer(Configuration.GetConnectionString("YYY")));
Saturniid answered 27/3, 2021 at 15:19 Comment(3)
no need to add ServiceLifetime.Scoped ? should I remove the UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)Trifocal
AddDbContext creates it as Scoped service. Other options are up to you.Saturniid
with some changes in my code and using @kingking advice I have no error nowTrifocal
S
22

I was getting this error because I was not using an await on a method inside a controller method. This was causing the function to return and dispose the context before the call had completed.

enter image description here

Stemma answered 25/1, 2022 at 15:48 Comment(1)
i had a similar scenario where you made an awaited call on database save. then, after a good save, the code makes another save. I forgot to await the second database call, as your example shows. Thanks!Capillarity
S
8

In asp.net core the DbContext should be a Scoped service, not a Singleton.

Change this:

services.AddDbContext<XXX>
                (option => 
                option.UseSqlServer(Configuration.GetConnectionString("YYY"))
                .ServiceLifetime.Singleton);

To

services.AddDbContext<XXX>
                (option => 
                option.UseSqlServer(Configuration.GetConnectionString("YYY")));
Saturniid answered 27/3, 2021 at 15:19 Comment(3)
no need to add ServiceLifetime.Scoped ? should I remove the UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)Trifocal
AddDbContext creates it as Scoped service. Other options are up to you.Saturniid
with some changes in my code and using @kingking advice I have no error nowTrifocal
G
0

I've met this problem by my mistake, for a background worker (registered as a HostedService serviceCollection.AddHostedService<BackgroundWorker>(); so it's considered as a singletone) I was using some repos and services in it, so i was using IServiceScopeFactory, i have something like

using var scope = serviceScopeFactory.CreateScope();

using var repo1 = scope.ServiceProvider.GetRequiredService<IRepo1>();
using (var repo2 = scope.ServiceProvider.GetRequiredService<IRepo2>())
{
    // some code
}

disposing the repo2 desposes the dbcontext, so whenever I try to access db from repo1 I'm getting this exception.

Gown answered 2/11 at 10:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.