Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Windows Azure, PHP, ...

NAVIGATION - SEARCH

Advanced ASP.NET caching events

Currently, I'm giving an ASP.NET classroom training at our company, which actually is quite good for me: I needed to refresh all ASP.NET concepts, as those all fade away slowly when you don't use them for a while... Now, one of those refreshed concepts is ASP.NET's caching.

ASP.NET offers a flexible built-in caching mechanism, providing you with a global "Cache" object in which you can get and put data which needs to be cached for a while. One of the cool things about ASP.NET caching is that it actually listens to what you want: if you need the cache to expire after 10 minutes, it does so. Also, when memory is needed for other actions on the webserver, ASP.NET will gently clean the cache depeding on cache item priorities.

As for many things in this world, every good thing also has a downside... And here's the downside for ASP.NET's caching: when an item is removed from cache, you'll have to know and react to that. No problem, you say, as you can simply use an if-statement to fix things up. Here's a DataDet which will be cached to infinity (or untill memory is needed):

[code:c#]

if (Cache.Get("myDataSet") == null) {
    // Re-fetch data
    // ... DataSet ds = ....

    Cache.Insert(
        "myDataSet", ds, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration
    );
}

[/code]

Great thing! But... What if I want to centralise cache creation? What if I want to log something everytime a cache item has been removed due to memory limits being reached? Luckily, ASP.NET provides an answer to that: the System.Web.Caching.CacheItemRemovedCallback delegate. This delegate can be used to ask ASP.NET to notigy you using a delegate of what is happening inside the cache when something is removed from it. Here's the delegate signature:

[code:c#]

void (string key, Object value, CacheItemRemovedReason reason);

[/code]

As you can see, you can get the key that's being removed, its current value, and the reason why the item is being deleted. These reasons can be: Expired, Removed, Underused, and DependencyChanged. I think these speak for themselves, no?

Now let's implement this: I'll create a CacheRetrievalManager which will update my cache whenever an item is removed from cache:

[code:c#]

using System;
using System.Web.Caching;

public class CacheRetrievalManager
{
    public void RemovedCacheItemHandler(string key, Object value, CacheItemRemovedReason reason)
    {
        switch (key)
        {
            case "myDataSet":
                // call method to re-fetch data and re-set cache
                // ...
                break;
        }
    }
}

[/code]

One thing left is to specify that this method should be called whenever a cache item is removed:

[code:c#]

// Insert in cache ONCE, recreation will be handled by CacheRetrievalManager
DataSet ds = ...;
Cache.Insert(
    "myDataSet", ds, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, CacheRetrievalManager.RemoveCacheItemHandler
);

[/code]

Now I know exactly why something is removed, and that I can even log when this happens. You can now further extend this into separate CacheRetrievalManagers for every object you which to cache, fetch data inside that manager, ...

blog comments powered by Disqus