How to Use LazyCache in Your .Net Core Application — Beginner’s Guide

Kalpani Ranasinghe
The Startup
Published in
5 min readJan 17, 2021

--

Recently, I was given a new task to implement a cache for the application that I’m working on. Since I haven’t had any experience in caches I wanted to do some research on the available cache implementations and found this interesting NuGet package called LazyCache.

LazyCache is a simple in-memory caching service. It has a developer-friendly generics based API and provides a thread-safe cache implementation that guarantees to only execute your cachable delegates once. Under the hood it supports Microsoft.Extensions.Caching to provide performance and reliability in heavy load scenarios.

Where should you use LazyCache for?

Before choosing some package, you should go through the documentation or a demo code to find out whether it can be used to achieve the specific requirement. So I found that the LazyCache suits for;

  1. Caching of database calls,
  2. Complex object graph building routines and
  3. Web service calls that should be cached for performance.

Download

To install LazyCache, run the following command in the Package Manager Console

PM> Install-Package LazyCache

Example on how to create a cache using LazyCache

Let’s see a simple use case of the lazy cache. For this example, think, I want to cache the products of a furniture shop. Assume the Product class contains the id, name, and price of a product as properties.

public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public Product(string id, string name, decimal price)
{
Id = id;
Name = name;
Price = price;
}
}

Then we can create another class and call it ProductCache. Inside that, we can create our cache service using the following line of code. By default, it uses a single shared cache under the hood, but you can configure this.

IAppCache cache = new CachingService();

Then we need a method to add and get data from the cache. Actually, with the features of the lazy cache, we can do both by the single GetOrAdd method in it. To implement it, we can create a method called checkCache() inside the product cache class and it will take one input which is the product Id.

public Product checkCache(string productId)
{
Func<Product> loadedProduct = () => LoadProduct(productId);
Product cachedResult = cache.GetOrAdd(productId, loadedProduct, DateTimeOffset.UtcNow.AddMinutes(15));
return cachedResult;
}

Inside this function, we first declare (but don’t execute) a func/delegate whose result we want to cache. Then we get our Product from the cache or build them in the LoadProduct() function and cache the results to access next time under the given key.

As you can see the magic happens in the GetOrAdd() method which gives the user an atomic and tidy way to add caching to your code. It leverages a factory delegate Func and generics to make it easy to add cached method calls to your app.

It means you avoid the usual “Check the cache, execute the factory function, add results to the cache” pattern, which saves you by writing the double locking cache pattern.

The default caching time is 20 minutes, so here I have changed it to 15 minutes.

public void InitResetCache()
{
cache.CacheProvider.Dispose();
var provider = new MemoryCacheProvider(
new MemoryCache(
new MemoryCacheOptions()));
cache = new CachingService(provider);
dummyData = new List<Product>();
dummyData.Add(new Product("product-01", "High Back Leather Chair", 34475.00m));
dummyData.Add(new Product("product-02", "Mid Back Leather Chair", 24475.00m));
dummyData.Add(new Product("product-03", "Low Back Leather Chair", 14475.00m));
dummyData.Add(new Product("product-04", "Visitor Chair", 24400.00m));
dummyData.Add(new Product("product-05", "Lecture hall chair", 7475.00m));
}

InitResetCache() function can be used to reset and initialize the cache. Inside it, it clears the cache and creates some dummy data to be used in the examples.

Flushing or clear the data can be achieved by disposing of the implementation of ICacheProvider which is typically the MemoryCacheProvider and then creating a new instance of CachingService with a new provider instance.

(Note — See the following also https://github.com/alastairtree/LazyCache/wiki/API-documentation-(v-2.x)#empty-the-entire-cache)

Inside the LoadProduct() function it iterates through the dummyData and finds the matching product by its Id.

public Product LoadProduct(string productId)
{
foreach (Product p in dummyData)
{
if(p.Id == productId)
{
return p;
}
}
return null;
}

Here’s the full ProductCache class for your reference.

public class ProductCache
{
IAppCache cache = new CachingService();
public List<Product> dummyData = new List<Product>();

public void InitResetCache()
{
cache.CacheProvider.Dispose();
var provider = new MemoryCacheProvider(
new MemoryCache(
new MemoryCacheOptions()));
cache = new CachingService(provider);
dummyData = new List<Product>();
dummyData.Add(new Product("product-01", "High Back Leather Chair", 34475.00m));
dummyData.Add(new Product("product-02", "Mid Back Leather Chair", 24475.00m));
dummyData.Add(new Product("product-03", "Low Back Leather Chair", 14475.00m));
dummyData.Add(new Product("product-04", "Visitor Chair", 24400.00m));
dummyData.Add(new Product("product-05", "Lecture hall chair", 7475.00m));
}
public Product checkCache(string productId)
{
Func<Product> loadedProduct = () => LoadProduct(productId);
Product cachedResult = cache.GetOrAdd(productId,
loadedProductDateTimeOffset.UtcNow.AddMinutes(15));
return cachedResult;
}
public Product LoadProduct(string productId)
{
foreach (Product p in dummyData)
{
if(p.Id == productId)
{
return p;
}
}
return null;
}
}

Yes, now we can check how this cache works. Before that, we need a simple handler class to manage the output.

public class ProductHandler
{
public ProductCache productCache = new ProductCache();

public Product GetProduct(string id)
{
return productCache.checkCache(id);
}
public void InitReset()
{
productCache.InitResetCache();
}
}

As you can see, it contains GetProduct() method which has one argument, ProductId, and inside it calls the product cache’s checkCache() function with the given id. And also it contains an InitReset() function which calls InitResetCache of the product cache.

Now let’s call the GetProduct() method and see what happens.

public class Program
{
public static void Main(string[] args)
{
ProductHandler productHandler = new ProductHandler();
productHandler.InitReset();
Product product1 = productHandler.GetProduct("product-03");
Product product2 = productHandler.GetProduct("product-01");
Console.WriteLine("Product Name : " + product1.Name + " Product Price : " + product1.Price);
Console.WriteLine("Product Name : " + product2.Name + " Product Price : " + product2.Price);
}
}

Following is the output.

Congratulations! now you know how to create a cache using LazyCache easily. You can find the source code for this example from here.

Before ending the article, I would like to name some alternatives for the lazy cache. Check them and let me know what do think. 😉

  1. Electron.NET
  2. CacheManager
  3. Akavache
  4. Foundatio
  5. EasyCaching

Yay! You have reached the end of this article. So, Let’s meet again with another article, full of new knowledge. Until then Stay safe! 😃

Thank you!

Reference

--

--

Kalpani Ranasinghe
The Startup

Backend Developer | Graduate Student at University of Oulu