Create a ASP.NET 2.0 web form project using this code.
using
public partial class WebForm1 : System.Web.UI.Page{ // we use this isToSleep to create the race condition for first call ItemRemovedCallback // if recursive calls happens, all the subsequent calls will not be delayed the the sleep call. private static bool isToSleep = true; protected void Page_Load(object sender, EventArgs e){ // This is request thread adding the item to the cache if (Cache.Get("Item01") == null) AddToCache("Item01", "Item01 Value");}
Analysis:1. Cached Item is added to the cache when the page is loaded.2. Cache Item is expired after 10 seconds.3. Item is removed from cache and CacheItemRemoved event is fired.4. CacheItemRemovedCallBack is called.5. CacheItemRemovedCallBack is put to sleep for 10 seconds to simulate the race condition.6. Page is refreshed and Item is added back to cache at this time. (This is a simulation of race condition under multiple users environment).7. Cache.Insert is called to add the item back to cache. What happens next is different under ASP.NET 1.1 and ASP.NET 2.0
Under 1.1:8. Cache.Insert finds the item is already in the cache. It will remove the item, fire the CacheItemRemoved event and then insert the item.
Under 2.0:8. Cache.Insert finds the item is already in the cache. It will fire the CacheItemRemoved event and CacheItemRemovedCallBack is called before the item is removed.9. CacheItemRemovedCallBack will invoke the Cache.Insert again and Insert sees the item is still in the cache and jump back to step 8.
Resolution and Conclusion:1. Use Cache.Add instead of Cache.Insert in the call back method will fix the problem.2. Refresh cache in the CacheItemRemovedCallBack is not a good practice. Try to refresh the cache when the page is load.