Skip to content

Troubleshooting LazyCache

Alastair Crabtree edited this page Dec 28, 2019 · 4 revisions

Create a minimal reproducable example of the problem

To get help with your issue it will make it much easier for others to help you if they can recreate your problem easily themselves without having all your application code. The simplest way to to that is to create a tiny console app that reproduces the problem you are having. Use the dotnet CLI and the code below as a starting point, and then file an issue here (slow response time - usually just the author!) or on stack overflow (faster - lots more people!). Often the process of doing this helps you to solve your own problem as an added bonus.

makedir minimal_repro
cd minimal_repro
dotnet new console
dotnet add package lazycache

And then in Program.cs place the following:

using System;
using LazyCache;

namespace minimal_repro
{
    class Program
    {
        static void Main(string[] args)
        {
            IAppCache cache = new CachingService();
            var result = cache.GetOrAdd("key", () => {
                Console.WriteLine("Hello from the cache!");
                return new object();
            });
            Console.ReadLine();        }
    }
}

Common issues

In-memory caching will always cache by reference to the object

LazyCache uses microsoft.extensions.caching.memory to actually cache your objects. This means that if you ask LazyCache to cache your object it will hold onto a reference to it (stopping it being garbage collected) and return the reference to the same instance of the object next time you ask for it.

If you modify something on that object outside of LazyCache then LazyCache will still return a reference to the same object, including any changes you have made to it.

To say it another way, LazyCache does not clone or copy the object you have built and cached - it just returns the same instance.

This is demonstrated in the following example:

IAppCache cache = new CachingService();

var cacheResult1 = cache.GetOrAdd("SomeLongCacheKey", 
  () => new ExampleClass() { Message = "Hello" );

// prints 'Hello'
Console.WriteLine(cacheResult1.Message);
           
var cacheResult2 = cache.GetOrAdd("SomeLongCacheKey", 
  () => new ExampleClass() { Message = "Nope - already cached" );

// prints 'Hello' from the first cached result
Console.WriteLine(cacheResult2.Message);
           
// changing the original cached object outside LazyCache
cacheResult1.Message = "Hola"; 
var cacheResult3 = cache.GetOrAdd("SomeLongCacheKey", 
  () => new ExampleClass() { Message = "Still nope" );

// prints 'Hola'
Console.WriteLine(cacheResult3.Message);

Caching bools and other value types - the default(bool) is false

Caching simple value types like a bool can be missleading and is best avoided because the default for a value type may not be what you expect.

If you retrieve a bool from the cache with value false that could occur because you cached the false value. But it could also be because the default value for a bool is false and the value did not exist in the cache!

Always cache the nullable flavour of value types so you can check for null and be certain if you hit the cache or missed, and avoid confusion with the default value.