Uniquify your cache keys

OK, I probably shouldn't have to make this post. As I keep making the mistake, there are only two possibilities: other people also make this mistake or I'm a unique idiot (as opposed to just another one).

When putting data into the ASP.NET Cache, make certain that your key is as unique as it needs to be. For example, you may need to read the data out of a local file for a control or other block of code. Here's the example from the docs (VB):

    Public Sub AddItemToCache(sender As Object, e As EventArgs)
        itemRemoved = false

        onRemove = New CacheItemRemovedCallback(AddressOf Me.RemovedCallback)

        If (IsNothing(Cache("Key1"))) Then
          Cache.Add("Key1", "Value 1", Nothing, DateTime.Now.AddSeconds(60), TimeSpan.Zero, CacheItemPriority.High, onRemove)
        End If
    End Sub
So, what's the problem? Well, what happens if you have two vroots that might call this? Well, the key is the same, so those two vroots would share the data. If that's what you've intended, great. However, I think it is much more likely that each vroot will need it's own unique set of data. Similarly, do all users share this same data? In the cases where data should not be shared across vroots or users, you should select keys that are appropriate. Including the vroot, sessionid or other "uniquifier" in the key is probably a good idea. 

I most recently made this mistake when writing a control that "would only ever be used in one vroot." By reflex, I wrote:

    private String LoadAndCache(String filename) {
        String result = null;
        String key = "Content";
        result = Cache[key] as String;
        if (null == result) {
            try {
                using (StreamReader reader = File.OpenText(filename)) {
                    result = reader.ReadToEnd();
                }
            } catch (Exception ex) {
                //error opening file
                Trace.Warn("Error Opening File " + ex.Message);
            }
        }
        //and cache
        Cache.Add(key, result,
            new CacheDependency(filename),
            Cache.NoAbsoluteExpiration,
            Cache.NoSlidingExpiration,
            CacheItemPriority.Normal, null);
        return result;
    }

Notice that the cache key is "Content". OK, as long as this only runs in a single vroot, or if everyone shares the content. Sadly, this was not the case. Testing created a number of vroots, and they were noticing that the data never changed. Ooops. The data should have been unique *per vroot*, as is often the case even if it should only ever run "in a single vroot." I changed the line bolded above to:

        String key = String.Format("Content4{0}", GetVRoot());

Alternately, if each user should have received their own version of the content, you should concatenate with the SessionID. Don't assume that a simple string key for cache items will be enough for the life of the code.

Print | posted on Monday, April 24, 2006 10:49 PM

Feedback

# re: Uniquify your cache keys

left by Anonymous at 4/24/2006 11:05 PM Gravatar
I've always thought there should be a "SessionCache" in the System.Web.Caching namespace. It would behave as if the Session and the Cache object had a child - automatically scoped to the session, but with weak references like the cache.

# re: Uniquify your cache keys

left by Anonymous at 4/25/2006 3:01 AM Gravatar
If you're writing a control, aren't you also apt to run into this problem simply when there are multiple instances of the control in the app? Unless that's what you intend, of course.
Comments have been closed on this topic.