-
Notifications
You must be signed in to change notification settings - Fork 159
API documentation (v 0.7.x)
Why use LazyCache? What's wrong with ObjectCache - caching without LazyCache
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());
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));
}
...
}
var products = cache.GetOrAdd("all-products", () => dbContext.Products.ToList(), DateTimeOffset.Now.AddMinutes(5));
var products = cache.GetOrAdd("all-products", () => dbContext.Products.ToList(), new TimeSpan(0, 5, 0));
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));
}
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 products to the cache for at most one minute
cache.Add("all-products", products, DateTimeOffset.Now.AddMinutes(1));
// 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));
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);
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");
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");
// Change the default cache duration from 20 minutes to 3 minutes
var cache = new CachingService() { DefaultCacheDuration= 60 * 3 };
You can extend the default behaviour easily enough, see Extending LazyCache