Skip to content

API documentation (v 0.7.x)

Alastair Crabtree edited this page Mar 20, 2019 · 1 revision

Why use LazyCache? What's wrong with ObjectCache - caching without LazyCache

Geting started

The best way to use LazyCache is through the GetOrAdd method. It uses generics to save you any type casting hassle and a Func to ensure you only call you cacheable delegate once.

// Create the cache
IAppCache cache = new CachingService();

// Get all products from the cache, or get from db and cache results
var products = cache.GetOrAdd("productService-getProducts", () => dbContext.Products.ToList());

Selecting a cache key

Each cache entry must have a unique key, where the key is unique to the underlying cache instance, which by default is the shared MemoryCache.Default.

Constructing a unique key is left to the developer, but a good best practice is to cache the results of a chosen methods call and adopt convention of className-methodName-argument1Value-argument2Value etc for the method you are adding caching to. Following this naming convention makes it easy to examine keys at run-time and establish the source and guarantees uniqueness.

For example

public class ProductService() {
...
    public Product GetProductById(int id){
        var key = string.Format("ProductService-GetProductById-{0}", id); //or use string interpolation
        return cache.GetOrAdd(key, () => dbContext.Products.Get(id));
    }
...
}

Change the cache duration - absolute expiration

var products = cache.GetOrAdd("all-products", () => dbContext.Products.ToList(), DateTimeOffset.Now.AddMinutes(5));

Change the default cache duration - sliding expiration

var products = cache.GetOrAdd("all-products", () => dbContext.Products.ToList(), new TimeSpan(0, 5, 0));

GetOrAdd an Async delegate/Task to the cache

In this example we demonstrate using lazy cache to cache an async Entity Framework query inside a webapi controller:

[HttpGet]
[Route("api/products")]
public async Task<Product> Get(int id)
{
    Func<Task<Product>> cacheableAsyncFunc = () => dbContext.Products.GetAsync(id);

    var cachedProducts = await cache.GetOrAddAsync($"ProductsController-Get-{id}", cacheableAsyncFunc);

    return cachedProducts;

    // Or just do it all in one line if you prefer
    // return await cache.GetOrAddAsync($"ProductsController-Get-{id}", () => dbContext.Products.GetAsync(id));
}

Add an item to the cache manually for the default duration (20 mins)

Most of the time all you need is GetOrAdd but sometimes you might need to force an item into the cache

// Get the cache
IAppCache cache = new CachingService();

// Get all products from db
var products = dbContext.Products.ToList();

// Add them to the cache so we can retrieve them up to 20 mins later
cache.Add("all-products", products);

Add an item to the cache for a custom duration (absolute expiration)

// Add products to the cache for at most one minute
cache.Add("all-products", products, DateTimeOffset.Now.AddMinutes(1));

Add an item to the cache for a custom duration (sliding expiration)

// Add products to the cache and keep them there as long as they 
// have been accessed in the last 5 minutes
cache.Add("all-products", products, new TimeSpan(0, 5, 0));

Custom cache policies

Get notified when something is removed, set cache entry priorities and more by using a CacheItemPolicy

// Add products to the cache with an unremovable custom cache policy 
// add a custom eviction callback
var policy = new CacheItemPolicy(){ 
   Priority= CacheItemPriority.NotRemovable, 
   RemovedCallback = args => log.Write("Products removed from cache")
};
cache.Add("all-products", products, policy);

If you need the last version of your cached data, you can access it by implementing a callback delegate that accepts a CacheEntryRemovedArguments argument.

private void OnCacheExpired(CacheEntryRemovedArguments arguments)
{
   var productsBeingRemovedFromCache = (List<Product>)arguments.CacheItem.Value;
}

And then registering the callback as part of your cache policy

var policy = new CacheItemPolicy(){ 
    RemovedCallback = OnCacheExpired
};
cache.Add("all-products", products, policy);

Retrieve something from the cache manually

If you have already cached something you can retrieve it, without the need for any type checking or casting, using Get. If its not cached null will be returned.

// Get the cache
IAppCache cache = new CachingService();

// Get product from the cache based on a key
var product = cache.Get<Product>("product-with-id-1");

Deleting/removing/clearing something from the cache

If it is cached it will be removed, if not no error will be thrown

// Remove the products from the cache
cache.Remove("all-products");

Configuring the default cache duration of 20 minutes

// Change the default cache duration from 20 minutes to 3 minutes
var cache = new CachingService() { DefaultCacheDuration= 60 * 3 };

Extending LazyCache

You can extend the default behaviour easily enough, see Extending LazyCache