Creating Custom Cache Dependency
Creating Custom Cache Dependency
Introduction
ASP.NET 2.0 offers you several ways to set a dependency between a cached item and a file(s), another cached item(s) or SQL Server database table. No doubt they
satisfy most of the real world needs. However, at times the features offered by
these dependencies are not sufficient. In such cases you can create your own
dependency and use it instead of inbuilt ones. In this article you learn how this can be accomplished.
The Scenario
Imagine that you are developing an order processing application. The orders
are received from various sources in the form of an XML file. Whenever an order
is received the corresponding XML file is created on the web server. Whenever a
new order is received you want some cached object to expire. At first glance you
may think of setting a file based cache dependency between the new XML file and
the cached object. However, there is a catch. The same folder also accepts many
other XML files and you do not want to expire your item when any such files are
received. Also, the names of the order files are not fixed. The only way to
isolate order files from the rest of the XML files is to check the root element
of the XML file. If the root element name is "order" then it is an order file
and you should consider it else you need to ignore it. As you might have guessed
that such logic can not be applied with the inbuilt cache dependency techniques.
The Solution
In order to tackle the above problem you need to create your own dependency.
ASP.NET provides a class called CacheDependency that resides in
System.Web.Caching namespace and represents the base class for all custom
dependency classes. For example, the SqlCacheDependency class that represents a
dependency between a cached object and SQL Server table is derived from
the CacheDependency base class. The CacheDependency base class is responsible for
removing an object from cache when the expiration condition is met. The
CacheDependency class provides a protected method called NotifyDependencyChanged()
that must be called by the inherited classes so that the dependent item gets
deleted from the cache.
In our example we will create a class called MyCacheDependency that inherits
from CacheDependency. Further, we will use a FileSystemWatcher to monitor the
web site root folder. When any new file arrives the FileSystemWatcher will
notify us by raising certain events. We will then check if the new file is an
order file i.e. root element name is order. If the new file is an order file
then we will call NotifyDependencyChanged() method to delete the dependent item.
Creating a custom cache dependency
To begin creating our custom cache dependency, create a new web site in
Visual Studio and add a new class file called MyCacheDependency.cs in the
App_Code folder. The complete source code of the class is given below:
public class MyCacheDependency:CacheDependency
{
private FileSystemWatcher watcher;
public MyCacheDependency()
{
watcher = new FileSystemWatcher
(HttpContext.Current.Request.PhysicalApplicationPath);
watcher.EnableRaisingEvents = true;
watcher.Created += new FileSystemEventHandler
(watcher_Created);
}
void watcher_Created(object sender, FileSystemEventArgs e)
{
if (Path.GetExtension(e.Name) == ".xml")
{
XmlDocument doc = new XmlDocument();
doc.Load(e.FullPath);
if (doc.DocumentElement.Name == "order")
{
base.NotifyDependencyChanged(sender, e);
}
}
}
}
Here, we created a class called MyCacheDependency that inherits from
CacheDependency class. Note that the CacheDependency class resides in the
System.Web.Caching namespace which must be imported at the top of your class
file.
Then we declared a variable of type FileSystemWatcher. The FileSystemWatcher
class residing in System.IO namespace allows you to monitor a folder for file
system changes such as file creation, modification, renaming and deletion.
In the constructor of the MyCacheDependency class we set the
FileSystemWatcher to monitor the root folder of the web site. We obtain physical
path of the web site using PhysicalApplicationPath property of the Request
object. Then we set the EnableRaisingEvents property of the FileSystemWatcher
instance to true. Setting this property to true will raise several events when
the monitored folder changes. We are interested to handle event related to file
creation and hence we attach an event handler to the Created event of
FileSystemWatcher instance.
When a new file is created on the monitored folder the FileSystemWatcher
instance will raise the Created event. The event handler of Created event checks
the extension of the new file. If it is an XML file (.xml) then it loads the
file in an XmlDocument class. The XmlDocument class resides in the System.Xml
namespace and represents the DOM parser of .NET framework. Then we check if the
root element name (DocumentElement.Name) is "order" and if it is "order" then we
call NotifyDependencyChanged() method of the base class CacheDependency. The
NotifyDependencyChanged() method takes two parameters - sender and event
argument. As the sender parameter we pass the reference of our class and as the
event argument parameter we pass an empty instance of EventArgs class. Thus we
send notification to CacheDependency class only if the new file is an order
file.
Using the dependency
Now that we have created the custom dependency its time to use it. Add a new
web form in the web site. Drag and drop a GridView control on the web form. In
the Page_Load event of the web form write the following code:
protected void Page_Load(object sender, EventArgs e)
{
if (Cache["myobject"] == null)
{
string[] files=Directory.GetFiles
(Request.PhysicalApplicationPath);
MyCacheDependency cd = new MyCacheDependency();
Cache.Insert("myobject",files, cd);
}
GridView1.DataSource = (string[])Cache["myobject"];
GridView1.DataBind();
}
Here, we check if an item named myobject exist in the Cache. If it does not
exist we call GetFiles() method of Directory class. The GetFiles() method
returns an array of files in a specified folder. We will store this array in the
cache. Then we create an instance of MyCacheDependency class and insert a new item named myobject in the cache along
with the newly created dependency. The GridView control is then bound with the
myobject array.
The following figure shows how the GridView looks like at run time.

Testing the dependency
In order to test whether our dependency is working as expected or not, create a new XML
file called Order1.xml in a folder other than the web site folder. The structure
of the XML file should resemble the following sample:
<?xml version="1.0" encoding="utf-8" ?>
<order>
<item>
<product>Keyboard</product>
<qty>2</qty>
</item>
<item>
<product>Mouse</product>
<qty>10</qty>
</item>
</order>
Note that the root element of the XML file is <order>. Also, create a new
text file with any arbitrary text. Save both the files.
Now run the web form so that it displays a list of files as shown above. Now
drag and drop the text file into the web site folder and refresh the browser
window. Since we have dropped a text file the listing displayed in the grid
should not change. This proves that the dependency has not yet deleted the
cached object. Now drag and drop the XML file and refresh the browser window.
Since we dropped an XML file and that too with <order> root element the grid
will list the newly added file. This proves that the cached object was
deleted and new one got created with the fresh request.