.NET provides a callback method when a cached item is being removed from memory. Knowing when your cached item is removed is a good way to help manage caching performance. Below we'll take a look at how to implement the callback function that notifies us when a cached object is removed. We'll then display which cached object was removed along with the reason.

First add a label: lblInfo and a button: btnRemove to your web form.

Now move to the code-behind. First import the System.Web.Caching namespace.

In your Page_Load add the following:

    Protected Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        If Not IsPostBack Then
            Dim evtRemove As CacheItemRemovedCallback
            evtRemove = New CacheItemRemovedCallback(AddressOf RemoveCallback)

            ' Add our new cached object, notice the onRemove callback
            Cache.Add("CacheMe", _
                "1 + 2 = 3", _
                Nothing, _
                Caching.Cache.NoAbsoluteExpiration, _
                System.TimeSpan.FromSeconds(5), _
                Caching.CacheItemPriority.Default, _
                evtRemove)
        End If
    End Sub

What we do there is create the CacheItemRemovedCallback which points to our RemoveCallBack method (yet to be created) which will handle an event when the cached item is removed. We then add our cache object as normal but we pass our CacheItemRemovedCallback object. We set the expiration for 5 seconds for the sake of testing, assuming you'll be playing around with the code.

Next create the RemoveCallback method:

    Protected Sub RemoveCallback(ByVal key As String, ByVal value As Object, ByVal reason As System.Web.Caching.CacheItemRemovedReason)
        Dim nfo as String = "Cache item: [" & key & "] <br />value: [" & value.ToString() & "] <br />was [" & reason.ToString() & "]"
        lblInfo.Text = nfo.ToString()
    End Sub

The RemoveCallback returns a key (the name of the cached object), a value (the value of the cached object), and a reason (DependencyChanged, Expired, Removed, UnderUsed). Then we create a string to show what and why the cached object was removed by using the above values respectively.

Finally add the button that removes the cached object:

    Protected Sub btnRemove_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRemove.Click
        ' Remove the cached item
        Cache.Remove("CacheMe")
    End Sub

The button's execution causes the cached item to be removed which in turn fires our callback function that we created above (RemoveCallback).

That's all there is to it. Now compile and run your app and play with the button. Also try letting the cache expire and refresh the page to see the different reasons for removing the cached object.

Update (5/29/2007 9:45AM): Some great advice from McGurk from the comments section of this post. I'm going to post the comments here because it's important to remember.

Whenever talking about cache and the CacheItemRemovedCallback it is always wise to remind people that you should NEVER re-add the item removed in this callback. Doing so can cause your application to bring down the worker process. Often this is because the item is being removed due to memory pressure, and re-adding the item will result in the cache immediately removing the item, which will result in the callback being called again. You can see the nasty loop you can get into.

For critical items set your priority on the item to an appropriate level. Use a pattern where you attempt to retrieve an item from the cache, and if it is not present retrieve it from storage (file, database, etc.), re-insert it in the cache and then return it to callers.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Comments

DotNetKicks.com

Saturday, May 26, 2007 6:32 AM

trackback

Trackback from DotNetKicks.com

How to use the CacheItemRemovedCallBack

mcgurk

Tuesday, May 29, 2007 3:29 PM

mcgurk

Whenever talking about cache and the CacheItemRemovedCallback it is always wise to remind people that you should NEVER re-add the item removed in this callback.  Doing so can cause your application to bring down the worker process.  Often this is because the item is being removed due to memory pressure, and re-adding the item will result in the cache immediately removing the item, which will result in the callback being called again.  You can see the nasty loop you can get into.

For critical items set your priority on the item to an appropriate level.  Use a pattern where you attempt to retrieve an item from the cache, and if it is not present retrieve it from storage (file, database, etc.), re-insert it in the cache and then return it to callers.

Tamer Yousef United States

Tuesday, November 06, 2007 5:58 PM

Tamer Yousef

this is a good point but it does not apply all the time, in my situation the item is removed from the cache because it expires because of the timing I have setup for it, at that point I have to create a new copy of the cache object with fresh data which is exactley what 'm looking for.

Denny Ferrassoli United States

Tuesday, November 06, 2007 6:34 PM

Denny Ferrassoli

Hi Tamer,
You're right and the cache object is built for exactly that. Developers just have to be aware that the application can remove objects to free up memory, especially if it's under significant load. If your object "Expired" you're probably ok. But if your object is constantly being "Removed" and you re-add it to the cache you could get stuck in a loop.

Either way I think it's a good idea to monitor your cache. Keep an eye on items that are "Removed" or "UnderUsed." You could even log these items to allow you to tweak your code for better performance.

There's also a great article by Gavin Joyce where he explains his "Reluctant Cache Pattern" which is an intuitive way for managing cache objects. Read more here: weblogs.asp.net/.../...eluctant-Cache-Pattern.aspx

Tess United States

Friday, May 16, 2008 3:03 PM

Tess

I think from the comments there is some confusion about the loop that you get into...
In the cacheitemremovedcallback the cacheitem is still alive, it is just marked for deletion and will be removed from cache right after the cacheitemremovedcallback is done.
If you reinsert the cacheitem with the same key, this deletes the old item (again) and inserts the new one, so the cacheitemremovedcallback is triggered again.  This is a recursive loop which has nothing to do with memory preassure or where you are at in the process, it will always happen, so you should never re-insert the item in the cacheitemremoved callback.  If you need it to be there permanently you should mark the cache item as non-removable.

You aslo need to be extremely careful with how you implement the cacheitemremovedcallback so that you don't implement it as an instance method of a page or a control or something to that effect, since the object that implements the eventhandler will stick around in memory for the duration that the object is cached.

See these two articles on the topic:
about the eventhandler memory leak
blogs.msdn.com/tess/archive/2006/08/11/695268.aspx

about the stackoverflow that results from the recursive loop if you re-insert the object in the cacheitemremovedcallback
blogs.msdn.com/.../...removedcallback-part-ii.aspx

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Denny Dot Net

Mmmmmm.... ASP.NET Code