Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is DBContext is disposed after putting it in IMemoryCache (.NET Core / EF Core)

I'm trying to put a subset of db-data in an IMemoryCache, but the 2nd time I call the application, I get an error:

ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context 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, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'WebDbContext'.

My Code snippet:

    public class ArticleRepository : IArticleRepository
    {
        private readonly WebDbContext _WebDbContext;
        private readonly IMemoryCache _cache;

        public ArticleRepository(WebDbContext WebDbContext, IMemoryCache cache)
        {
            _WebDbContext = WebDbContext;
            _cache = cache;
        }

        public IQueryable<Articles> WebshopArticles
        {
            get
            {
                return _cache.GetOrCreate("WebshopArticles", entry =>
                {
                    entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
                    return _WebDbContext.Article.Include(s => s.Details);
                });                
            }
        } 

        public IQueryable<Articles> GetArticles(string category)
        {
            return WebshopArticles.FirstOrDefault(s => s.Category == Category);
        }
    }

It looks like DBContext is disposed after the first time I put it in cache. How can i handle this?

like image 920
CribAd Avatar asked Dec 18 '22 20:12

CribAd


1 Answers

You're using dependency injection to get an instance of your WebDbContext through your constructor. ASP.NET Core does this by initiating a WebDbContext object for you and injecting it into the constructor call when it creates an instance of your repository class.

But that WebDbContext object is only available for the life of the current HTTP request. Once that HTTP request is complete, ASP.NET Core gets rid of it. That's why you see it disposed.

Update: I see what you're doing. The problem is here:

return _WebDbContext.Article.Include(s => s.Details);

That does not cache the data. That caches the query (IQueryable). The query doesn't get executed until you enumerate that (loop through it). This is refered to as "lazy loading". So your GetArticles actually performs the query again each time it's called.

The first time you use it (in the same HTTP request you cached it), it works. But when you use it the second time, the context is disposed and the query can't be executed.

You need to force it to execute the query right away. An easy way is to call ToList():

return _WebDbContext.Article.Include(s => s.Details).ToList();

You'll need to change the property type to IEnumerable too.

like image 145
Gabriel Luci Avatar answered May 14 '23 07:05

Gabriel Luci