MichaCo / CacheManager

CacheManager is an open source caching abstraction layer for .NET written in C#. It supports various cache providers and implements many advanced features.
http://cachemanager.michaco.net
Apache License 2.0
2.34k stars 456 forks source link

ObjectDisposedException in BaseCacheManager #205

Closed erizzo closed 6 years ago

erizzo commented 6 years ago

In an app using CacheManager, deployed in Azure, we're occasionally seeing exceptions like this:

Log_message:ID: 810e066b-61da-4214-8ffa-ff1c82e11bc8Cannot access a disposed object. Object name: 'BaseCacheManager1'.Exception_message:Type: ObjectDisposedException. Source: CacheManager.Core. Message: Cannot access a disposed object. Object name: 'BaseCacheManager1'. HResult: -2146232798 HelpLink: Data: null. STACK TRACE: at CacheManager.Core.Internal.BaseCache1.CheckDisposed() at CacheManager.Core.BaseCacheManager1.PutInternal(CacheItem`1 item) at D.S.Api.Security.ClaimsCachingMiddleware.d__2.MoveNext()...

When it happens, we see hundreds or thousands of them - basically every call to CacheManager. Still trying to figure out a reproducible scenario, and what may be happening at the time (isn't cloud development fun?) - in the meantime, any thoughts about it? Could you add some logging and/or defensive programming around that are to help avoid and/or troubleshoot it?

MichaCo commented 6 years ago

Hi @erizzo, Yup that sounds fun. Regarding the dispose mechanism, I don't think I can add anything more to it than throwing an Exception if someone tries to use a disposed CacheManager instance. This is already the "guard" check to prevent issues with disposed dependencies, which might occur later and might be even more verbose.

Dispose is a standard mechanism in .NET. and CacheManager just implements IDisposable so that resources or connections to cache servers can be closed etc. If cacheManagerInstance.Dispose() was invoked (manually or via a using statement or DI), an internal flag will be set which indicates that the instance cannot be used anymore. This flag gets checked on any method call and if it is set, the exception will be thrown. And there is no way to re-initialize a disposed instance. All that's by design and how disposable is supposed to work I think ;)

This means that you might have a scenario in your code which references and uses a disposed instance.

First of all, you should figure out why the instance gets disposed. I guess you never actually manually invoke Dispose or put a using around the instance?

Hint: If you have a website with DI, the DI system might dispose all singletons on app shutdown/crash.

MichaCo commented 6 years ago

/closeing for now, let me know if think I can assist or if you have a project to reproduce the behavior