Don't get me wrong, I really like the Asp.Net Cache (or HttpRuntime.Cache or Uncle Daddy if you want to call it that... you're a little odd aren't you?), but sometimes it just can't be trusted. I mean, I just gave you (the cache) my precious object a second ago and now you claim you don't have it? Did you lose it? Did you sell it on eBay? Did you pawn it to support your habit? Please at least tell me you got a decent price for it.
One of the great things about the cache is also what makes it so untrustworthy. Objects stored there are referenced with WeakReference so if your sever starts getting low on memory GC will collect objects from the cache to free some up. Also take into account that if you put an object in Cache and set it to expire after X minutes, when you go back to retreive it, do you really know how long it's been?
So what we want is a way to tell the cache "I want this specific object (a yellow Tonka dumptruck, metal, not plastic) and if you don't have it, here are instructions on how to get it".
Something like this:
using System;
using System.Reflection;
using System.Web;
using System.Web.Caching;
using log4net;
public delegate bool Factory<T>( out T instance );
public class CacheHelper
{
private static readonly ILog log =
LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType );
private static readonly Cache cache = HttpRuntime.Cache;
private CacheHelper(){}
public static T GetFromCache<T>(string key, int cacheTimeInMinutes, Factory<T> retrieveMethod) where T:class
{
T target = cache[key] as T;
if(target == null)
{
log.Info( "Cache miss for key:" + key + " type:" + typeof(T));
if(retrieveMethod(out target))
{
cache.Insert( key, target, null, DateTime.Now.AddMinutes( cacheTimeInMinutes ),
Cache.NoSlidingExpiration, CacheItemPriority.Normal, OnRemove );
}
}
else
{
log.Info( "Cache hit for key:" + key + " type:" + typeof(T));
}
return target;
}
public static void OnRemove( string key, object cacheItem, CacheItemRemovedReason reason )
{
log.Info( "Object removed from cache: Key-" + key + ": Reason-" + reason);
}
public static void RemoveFromCache(string key)
{
cache.Remove( key );
}
}
Usage would look like this:
List<string> searchList = CacheHelper.GetFromCache<List<string>>(
key,
5,
delegate( out List<string> instance ) { return SomeClass.GetSearchList( key, out instance ); } );
I call it the code equivalent of "Trust but verify".
Posted
03-06-2008 10:04 PM
by
anortham