I have created a async cache that uses .NET MemoryCache underneath.
This is the code:
public async Task GetAsync(string key, Func
Although there is an already accepted answer, I'll post a new one with Lazy approach. Idea is: to minimize the duration of lock block, if the key doesn't exists in cache, put a Lazy to cache. That way all threads using the same key at the same time will be waiting the same Lazy's value
public Task GetAsync(string key, Func> populator, TimeSpan expire, object parameters)
{
if (parameters != null)
key += JsonConvert.SerializeObject(parameters);
lock (_cache)
{
if (!_cache.Contains(key))
{
var lazy = new Lazy>(populator, true);
_cache.Add(key, lazy, DateTimeOffset.Now.Add(expire));
}
}
return ((Lazy>)_cache.Get(key)).Value;
}
Version2
public Task GetAsync(string key, Func> populator, TimeSpan expire, object parameters)
{
if (parameters != null)
key += JsonConvert.SerializeObject(parameters);
var lazy = ((Lazy>)_cache.Get(key));
if (lazy != null) return lazy.Value;
lock (_cache)
{
if (!_cache.Contains(key))
{
lazy = new Lazy>(populator, true);
_cache.Add(key, lazy, DateTimeOffset.Now.Add(expire));
return lazy.Value;
}
return ((Lazy>)_cache.Get(key)).Value;
}
}
Version3
public Task GetAsync(string key, Func> populator, TimeSpan expire, object parameters)
{
if (parameters != null)
key += JsonConvert.SerializeObject(parameters);
var task = (Task)_cache.Get(key);
if (task != null) return task;
var value = populator();
return
(Task)_cache.AddOrGetExisting(key, value, DateTimeOffset.Now.Add(expire)) ?? value;
}