A New Approach to HttpRuntime.Cache Management
page 3 of 9
by David Penton
Feedback
Average Rating: 
Views (Total / Last 10 Days): 68946/ 131

The Next Step - The Singleton Pattern

The Singleton pattern can help us out quite a bit. My favorite discussion of the Singleton pattern is here: http://www.yoda.arachsys.com/csharp/singleton.html. Note the first version is very similar to our example. Although it is marked as bad code by the author J one thing to consider about this article is that the variables that are being saved into have a global scope (as in, can be accessed in some way globally). Our variables are not static, but privately scoped to the calling method. So, let us review the second version in our example.

Listing 2

private static readonly object locker = new object();
 ...
 string key = "myCustomObjKey";
 
// attempt to retrieve the data from the cache
 CustomObj customObj = HttpRuntime.Cache[ key ] as CustomObj;
 
 
// now check the local variable
 if ( customObj == null )
 {
     // lock access here
    lock ( locker )
     {
        // check one more time
        customObj = HttpRuntime.Cache[ key ] as CustomObj;
 
 
        // now check the local variable
         if ( customObj == null )
         {
             // the object was null.  We need to repopulate it
             customObj = GetCustomObj();
 
             // place it in the cache
             HttpRuntime.Cache.Insert(
                 key
                 , customObj
                 , null
                 , DateTime.Now.AddMinutes( 10 )
                 , Cache.NoSlidingExpiration
                 );
         }
    }
}
 
 // now it is assumed to be set.  We return it to the caller
 return customObj;

Here, we lock on a private static readonly object. Now, any time there is no data to be found in the cache, there will only be a single request that will be able to repopulate the cache. Every time this is the case, every user requesting this data will wait on the "lock" except the first request. As soon as the lock is released, every user will benefit from the newly populated data. So, the question that should be raised here is how to generalize this pattern so that it is easy to accomplish?  Let consider another scenario as well.

In a typical website, there could be many different snippets of code just like this, retrieving many diverse kinds of data from various sources. It is also likely that in some applications, data needs to stay in cache or just needs to be "fresh" after a certain time. This automatic "refresh" would typically need to wait until the data expired from cache. So, how should we generalize this pattern for any case?  What about strongly typed access as well? Wouldn't that be nice?

New Caching Pattern

Let me introduce the signature for TCache<T>.Get:

Listing 3

public class TCache<T>
{
    /// <summary>
    /// For safety populating and retrieving data from the HttpRuntime Cache
    /// </summary>
    /// <param name="key">The cache key</param>
    /// <param name="refreshIntervalInSeconds">How long to retain in cache</param>
    /// <param name="loaderDelegate">How to load the cache</param>
    /// <returns>The object data requested</returns>
    public static T Get(string key, int refreshIntervalInSeconds
        , TCache.CacheLoaderDelegate loaderDelegate)
    { . . . }
}

Now, let us reveal the new Cache pattern with this new method.

Listing 4

CustomObject obj = TCache<CustomObject>.Get(
    "myCustomObjKey" // cache key we are using
    , 5 // number of seconds to keep in the cache
    , delegate() // this is the callback that populates the cache
    {
        return new CustomObject();
    });

TCache<T>Get consists of the pattern (simplified for article):

object o = TCache.Get( key );
if ( IsObjectNotT<T>( o ) )
{
    lock ( locker )
    {
        o = TCache.Get( key );
        if ( IsObjectNotT<T>( o ) )
            o = TCache.InternalCallback( key );
    }
}
if ( IsObjectT<T>( o ) ) return (T)o;
return default(T);

The InternalCallback method manages the delegate that was passed into TCache<T>.Get() from above and inserts the item into the cache.


View Entire Article

User Comments

No comments posted yet.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-05-18 11:33:16 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search