-
Website
http://john-sheehan.com/blog -
Original page
http://john-sheehan.com/blog/index.php/pluggable-aspnet-cachemanager/ -
Subscribe
All Comments -
Community
-
Top Commenters
-
smnbss
1 comment · 1 points
-
kevinpang
4 comments · 1 points
-
robconery
2 comments · 13 points
-
Craigslist Proxy
2 comments · -1 points
-
jeromepineau
2 comments · 1 points
-
-
Popular Threads
-
jQuery Snippets for Visual Studio 2010
3 weeks ago · 2 comments
-
RestSharp
3 weeks ago · 1 comment
-
jQuery Snippets for Visual Studio 2010
One thing though, and that is that in your implementations of the Get-method you access the storage twice. One time to check if there is anything in storage, and another time to actually get it. Since you don't lock anything, another thread can remove the item you are looking for. This will happen when you use the storage frequently.
Something like the following will solve this.
public T Get<T>(string key)
{
T item = (T)HttpContext.Current.Cache[key];
if (item == null)
item = default(T);
return item;
}
return HttpRuntime.Cache[key] as T;
This will automatically return default(T) if the cached item doesn't exist. Using Maarten's code if you try to get an object from the cache that can not correctly cast to the type T you will get can't convert exception for the object.
var item = HttpRuntime.Cache[key];
return item is T ? (T) item : default(T);
Which is basically what the as operator does anyway.
I can offer some insight into the model that John was following when he created the cache manager. Following a pattern similar to this allows you to create loosely coupled code.
With your question if you implemented the caching solution using only the specific classes if you ever decided you wanted to change your caching backing store from HttpRuntime.Cache (note: John, you should reference the cache as HttpRuntime.Cache instead of Httpcontext.Current.Cache, calling the context just causes extra processing to just resolve to HttpRuntime.Cache) to a sql data store or to a memory caching solution like memcache or velocity you will now have to go into you code and change every single usage of RequestProvider to use MemCacheProvider or whatever other implementation you wish to use.
With a loosely coupled implementation that John created here, if you ever wish to switch from one provider to another you only ever need to change where it instantiates CacheManger to use the new provider instead. This brings me to my point about Enterprise Library's CacheManager having a factory method for creating the caching providers usage, this will allow you to only need to declare the CacheProviders once in your code and no matter how many times you change the concrete implmentation of ICacheProvider you will only ever need to change 1 line of code in the entirety of your project which is a great thing indeed.
This idea of creating shared services that you can plug and play based off of interfaces is the basis of the idea of "Inversion of Control" or IoC that creates very robust and completely decoupled projects. Some of the most well known IoC frameworks are Microsoft's Unity, Spring.NET, Castle Windsor, Ninject, StructureMap to name a few there are quite a bit of frameworks out there for IoC. Creating loosely coupled code is definitely getting to the point where it is mandatory for a project to be a well made solution.
ICacheProvider cache = new ShortTermProvider();
or
CacheManager cache = new CacheManager(new ShortTermProvider());
http://msdn.microsoft.com/en-us/library/cc30910...
The big difference in implementation of the Caching block is that the providers are created through a singleton factory which in my opinion makes alot of sense since cache stores generally are only ever 1 and only 1 per type of store so relying on a factory to handle the management of instances of the providers makes sense to me more than doing new __Provider(....) anytime you wish to access the cache.
public static Cache Cache {
get {
if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Cache != null)
return System.Web.HttpContext.Current.Cache;
return System.Web.HttpRuntime.Cache;
}
}
That allows me to utilize the same concepts in Windows Forms and Windows Service applications....just some FYI
You should take a look at some Dependency Injection framework (castle, spring.net, Nunit) and apply it instead of creating new CacheManager directly in code.
I'm a fan of the whole loosely coupled thing, however there are some times that I require (well, want more then require) a few different caching strategies for one project. Very data dependent of course. Any thoughts?
The example above is perfect for if you need different caching strategies in a project. Just create a provider for each strategy and use that provider when needed.
lock the cache when you're writing to it, for occasions where data is being refreshed by another process.
lock (HttpContext.Current.Cache)
{
}
discussing locks and caching (at least in regards to ASP.NET) before. I
think it would be interesting to hear what the risk is of not using a lock.
public delegate T GetObjectDelegate<T>();
public V GetItemValue<V>(string objectID, V nullValue, GetObjectDelegate<V> getobject)
{
if (Cache[objectID] == null)
{
if (getobject == null)
return default(V);
V obj = getobject();
if (obj != null)
{
Insert(objectID, obj);
return obj;
}
else
return nullValue;
}
return (V)Cache[objectID];
}
in this way you'll be able to verify if an object is in cache and load the object in cache if it's not just in a single line
CacheManager.GetItemValue("key", null, delegate(){return getobjfromdb();})