I wanted to add this simple class that I find myself using all the time in every project that I create. It is a generic caching class:
CacheProvider`1.cs
public abstract class CacheProvider<TCache> : ICacheProvider
{
public int CacheDuration
{
get;
set;
}
private readonly int defaultCacheDurationInMinutes = 30;
protected TCache _cache;
public CacheProvider()
{
CacheDuration = defaultCacheDurationInMinutes;
_cache = InitCache();
}
public CacheProvider(int durationInMinutes)
{
CacheDuration = durationInMinutes;
_cache = InitCache();
}
protected abstract TCache InitCache();
public abstract bool Get<T>(string key, out T value);
public abstract void Set<T>(string key, T value);
public abstract void Set<T>(string key, T value, int duration);
public abstract void Clear(string key);
public abstract IEnumerable<KeyValuePair<string, object>> GetAll();
}
ICacheProvider.cs
public interface ICacheProvider
{
/// <summary>
/// Retrieve cached item
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Name of cached item</param>
/// <param name="value">Cached value. Default(T) if
/// item doesn't exist.</param>
/// <returns>Cached item as type</returns>
bool Get<T>(string key, out T value);
/// <summary>
/// Insert value into the cache using
/// appropriate name/value pairs
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="value">Item to be cached</param>
/// <param name="key">Name of item</param>
void Set<T>(string key, T value);
/// <summary>
/// Insert value into the cache using
/// appropriate name/value pairs WITH a cache duration set in minutes
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Item to be cached</param>
/// <param name="value">Name of item</param>
/// <param name="duration">Cache duration in minutes</param>
void Set<T>(string key, T value, int duration);
/// <summary>
/// Remove item from cache
/// </summary>
/// <param name="key">Name of cached item</param>
void Clear(string key);
IEnumerable<KeyValuePair<string, object>> GetAll();
}
I tend to use dependency injection to implement this cache. Here is a concrete implementation of my cache provider:
public class HttpCache : CacheProvider<Cache>
{
protected override Cache InitCache()
{
return HttpRuntime.Cache;
}
public override bool Get<T>(string key, out T value)
{
try
{
if (_cache[key] == null)
{
value = default(T);
return false;
}
value = (T)_cache[key];
}
catch
{
value = default(T);
return false;
}
return true;
}
public override void Set<T>(string key, T value)
{
Set<T>(key, value, CacheDuration);
}
public override void Set<T>(string key, T value, int duration)
{
_cache.Insert(
key,
value,
null,
DateTime.Now.AddMinutes(duration),
TimeSpan.Zero);
}
public override void Clear(string key)
{
_cache.Remove(key);
}
public override IEnumerable<KeyValuePair<string, object>> GetAll()
{
foreach (DictionaryEntry item in _cache)
{
yield return new KeyValuePair<string, object>(item.Key as string, item.Value);
}
}
}
View the source on GitHub: Omegaluz.Caching
Update, here is a new article with an example: Using the C# generic cache: the Tester Doer pattern
very gcool Andy, thanks!
Beautiful!
Gee whiz, this is great!
looks similar to mine, but I dont see a cache invalidate function. sometimes I need to invalidate the cache, but I wont rebuild it unless a client request it. The data that gets cached could have multiple changes before the next request. Also you could pass in a function that rebuilds the cache so when the cache automatically invalidates it has option to rebuild based on that action.
Thanks for the feedback. I’ve never had a use for that functionality. Can you describe a specific use case. I’d love to see how you’ve implemented that.
Pingback: Using the C# generic cache: the Tester Doer pattern ← Code is Hard