Cache Item is null during refresh

Topics: Caching Application Block
Oct 28, 2008 at 4:30 PM
Edited Oct 29, 2008 at 10:01 AM
Hi, I'm using the Caching Application Block. I add an item with a refresh action as shown below. When the refresh action is actually called and at the same time you are trying to retrieve a value, there is a real danger that the value may be null. The only way around this is to constantly check for null and keep trying to retrieve the cached item. This to me is a bug, it should be up to the developer to remove the cached item themselves in the refresh action if they so choose should it not? Am I going wrong somewhere?

this.cacheManager = CacheFactory.GetCacheManager();
this.cacheManager.Add(key, value, CacheItemPriority.Normal,
new MyRefreshAction, new SlidingTime(new TimeSpan(0, 0, 5)));
Thread.Sleep(5000);
for (int i = 0; i < 1000; ++i)
{
string value = this.cacheManager.GetData(key)
// THERE IS A DANGER THAT VALUE MAY BE NULL DUE TO A REFRESH UNDER WAY
}

[Serializable]
public sealed class MyRefreshAction : ICacheItemRefreshAction
{
public void Refresh(string removedKey, object expiredValue, CacheItemRemovedReason removalReason)
{
// MY ITEM HAS BEEN REMOVED HERE AND IF I TRY TO RETRIEVEIT, IT WILL BE NULL
CacheManager cacheManager = CacheFactory.GetCacheManager("CacheManager");
if (removalReason == CacheItemRemovedReason.Expired)
{
cacheManager.Add(removedKey, "Updated");
}
}
}
Oct 30, 2008 at 3:20 PM
Edited Oct 30, 2008 at 3:26 PM
I don't think it's a bug.  As the parameter "removedKey" in the Refresh method indicates, the item is indeed removed from the cache item.  See this thread http://www.codeplex.com/entlib/Thread/View.aspx?ThreadId=17096, hope it would clear some things up.  I haven't read the book mentioned there, maybe it would help too.
Oct 31, 2008 at 10:37 AM
Edited Oct 31, 2008 at 10:40 AM
I think it should be up to you to decide what happens when a cache item expires. Having it automatically removed for you requires you to write code like this:

public object GetCacheItem(string key)
{
object cacheItem = cache[key];
if (cacheItem == null)
{
// Wait for the item to be refreshed, maybe do something else while your waiting.
}
return cacheItem.
}

All refreshes should take place in the RefreshAction in my opinion. Maybe I'm missing something and there is a very good design decision to do this but I think it leads to extra work fro the developer.
Nov 3, 2008 at 3:25 AM
What do you want to do when refresh fires?  Do you want to update the item's value before adding it again to the cache? Or do you simply want to keep the cache item alive all the time and has no dependency?  If this is the case, you can simply pass a NeverExpired object when creating a cache item.  This is an ICacheItemExpiration object. There are other classes in Entlib which implements this interface.  If none of those suit your need, you can always create your own implementation.
Nov 3, 2008 at 9:37 AM
I want to update the item's value before adding it again to the cache.
Nov 5, 2008 at 4:06 AM
Hi Rehan,  I see your point.  I need to verify is this is an issue.  As a workaround, you can implement your own ICacheItemExpiration.  In the HasExpired() method, check if the item has already expired and if so, update the item's value and always return false.  With this, you can avoid getting a null item.  I'll get back to you as soon as I have an answer.


Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
sarah.b.urmeneta@avanade.com