How to: Notify an Application When an Item Is Removed from the Cache
In most cache scenarios, when an item is removed from the cache, you do not need to put it back into the cache until it is needed again. The typical development pattern is to always check the cache for the item before using it. If the item is in the cache, you use it. If it is not in the cache, you retrieve the item again and add it back to the cache.
However, in some cases it is useful for your application to be notified when an item is removed from the cache. For example, you might have a cached report that takes considerable processing time to create. When it is removed from the cache, you want it to be regenerated and put into the cache immediately so that the next time it is requested, the user does not have to wait for it to be processed.
To enable notification of items being removed from the cache, ASP.NET provides the CacheItemRemovedCallback delegate. The delegate defines the signature to use when you write an event handler that is called in response to an item being removed from the cache. ASP.NET also provides the CacheItemRemovedReason enumeration, which is used to specify the reason for cache item removal.
Typically, you implement the callback by creating a handler in a business object that manages the particular cache data that you are trying to retrieve. For example, you might have a ReportManager
object that has two methods, GetReport
and CacheReport
. The GetReport
report method checks the cache to see if the report is already cached and if it is not, the method regenerates the report and caches it. The CacheReport
method has the same function signature of the CacheItemRemovedCallback delegate; when the report is removed from cache, ASP.NET calls the CacheReport
method, which then re-adds it to the cache.
To notify an application when an item is removed from the cache
Create a class that is responsible for retrieving the item from the cache and handling the callback method to add the item back into the cache.
In the class, create a method that adds an item to the cache.
In the class, create a method that gets an item from the cache.
Create a method that handles the cache item removal callback. The method must have the same function signature as the CacheItemRemovedCallback delegate. In the method, perform the logic you want to run when the item is removed from the cache, such as regenerating the item and adding it back into the cache.
To test the cache item callback
Create an ASP.NET Web page that calls the method in your class that adds the item to the cache.
The following code example shows how to call the
GetReport
method of theReportManager
class (defined in the example that follows the procedure). It then displays the report in a Label control namedLabel1
during the page's Page_Load method.protected void Page_Load(object sender, EventArgs e) { this.Label1.Text = ReportManager.GetReport(); }
Protected Sub Page_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load Me.Label1.Text = ReportManager.GetReport() End Sub
Request the ASP.NET page in a browser and view the report.
The report is created the first time the page is requested, and subsequent requests will access the report from the cache until the report is removed.
Example
The following code example shows a complete class named ReportManager
that handles notification when an item is deleted from the cache. The class manages a report in the form of a string that represents a long-running process.
Although the example uses a class declared as static (Shared in Visual Basic), it is not required that you use a static class. However, the method that will handle the callback must exist when the cache item is deleted. For example, you should not implement the callback handler in an ASP.NET page, because the page might have been disposed of by the time the item is deleted from the cache and therefore the method to handle the callback will not be available. Using a static class for the method that handles the callback ensures that the method will still exist when the item is removed from cache. However, the drawback to a static class is that all static methods need to be thread safe.
Caution |
---|
Do not set the CacheItemRemovedCallback to a method in a page. In addition to a page method not being available for a callback after the page is disposed of, pointing the callback to a page method can prevent the memory used by the page from being reclaimed by garbage collection. This happens because the callback contains a reference to the page and the garbage collector will not remove an item from memory if the item has any references. During periods of application load, this could cause memory to be used up very quickly. |
The example class includes these features:
A private member for tracking whether the report has been removed from the cache.
A method named
CacheReport
that adds an item to the cache under the nameMyReport
and sets the item to expire one minute after being added to the cache. The method also passes theReportRemovedCallback
method to the onRemoveCallback parameter, which registers theReportRemoveCallback
method so it is called when the item is deleted from cache.A method named
GetReport
that gets an item from the cache. The method determines whether the item namedMyReport
exists in the cache. If the item does not exist, the method callsCacheReport,
which adds the item to the cache.A method named
ReportRemovedCallback
that handles the cache item removal callback.ReportRemovedCallback
has the same function signature as the CacheItemRemovedCallback delegate. The method sets the variable _reportRemovedFromCache
to true and then adds the item back to the cache via theCacheReport
method.
using System;
using System.Web;
using System.Web.Caching;
public static class ReportManager
{
private static bool _reportRemovedFromCache = false;
static ReportManager()
{ }
public static String GetReport()
{
lock (typeof(ReportManager))
{
if (HttpContext.Current.Cache["MyReport"] != null)
return (string)HttpRuntime.Cache["MyReport"];
else
{
CacheReport();
return (string)HttpRuntime.Cache["MyReport"];
}
}
}
public static void CacheReport()
{
lock (typeof(ReportManager))
{
HttpContext.Current.Cache.Add("MyReport",
CreateReport(), null, DateTime.MaxValue,
new TimeSpan(0, 1, 0),
System.Web.Caching.CacheItemPriority.Default,
ReportRemovedCallback);
}
}
private static string CreateReport()
{
System.Text.StringBuilder myReport =
new System.Text.StringBuilder();
myReport.Append("Sales Report<br />");
myReport.Append("2005 Q2 Figures<br />");
myReport.Append("Sales NE Region - $2 million<br />");
myReport.Append("Sales NW Region - $4.5 million<br />");
myReport.Append("Report Generated: " + DateTime.Now.ToString()
+ "<br />");
myReport.Append("Report Removed From Cache: " +
_reportRemovedFromCache.ToString());
return myReport.ToString();
}
public static void ReportRemovedCallback(String key, object value,
CacheItemRemovedReason removedReason)
{
_reportRemovedFromCache = true;
CacheReport();
}
}
Imports System
Imports System.Web
Imports System.Web.Caching
Public Class ReportManager
Private Shared _reportRemovedFromCache As Boolean = False
Shared Sub New()
End Sub
Private Sub New()
End Sub
Public Shared Function GetReport() As String
SyncLock (GetType(ReportManager))
If HttpContext.Current.Cache("MyReport") IsNot Nothing Then
Return CStr(HttpRuntime.Cache("MyReport"))
Else
CacheReport()
Return CStr(HttpRuntime.Cache("MyReport"))
End If
End SyncLock
End Function
Public Shared Sub CacheReport()
SyncLock (GetType(ReportManager))
HttpContext.Current.Cache.Add("MyReport", CreateReport(), _
Nothing, DateTime.MaxValue, New TimeSpan(0, 1, 0), _
System.Web.Caching.CacheItemPriority.Default, _
AddressOf ReportRemovedCallback)
End SyncLock
End Sub
Private Shared Function CreateReport() As String
Dim myReport As New System.Text.StringBuilder()
myReport.Append("Sales Report<br />")
myReport.Append("2005 Q2 Figures<br />")
myReport.Append("Sales NE Region - $2 million<br />")
myReport.Append("Sales NW Region - $4.5 million<br />")
myReport.Append("Report Generated: " & _
DateTime.Now.ToString() & "<br />")
myReport.Append("Report Removed From Cache: " _
& _reportRemovedFromCache.ToString())
Return myReport.ToString()
End Function
Public Shared Sub ReportRemovedCallback(ByVal key As String, _
ByVal value As Object, ByVal removedReason _
As CacheItemRemovedReason)
_reportRemovedFromCache = True
CacheReport()
End Sub
End Class
See Also
Tasks
How to: Add Items to the Cache
How to: Retrieve Values of Cached Items
How to: Delete Items from the Cache in ASP.NET
Concepts
ASP.NET Caching Overview
What's New in ASP.NET Caching
Cache Configuration in ASP.NET
Caching Application Data