Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

ASP.NET Caching Dependencies

4.26/5 (22 votes)
28 Jul 20066 min read 2   1.8K  
A discussion on caching in ASP.NET 2.0

Introduction

The concept of Caching was introduced in ASP.NET 1.X and has been improved significantly in ASP.NET 2.0. Caching allows you to store commonly used items in the memory and thus not create them from scratch when they are requested. There are different types of Caching available in the .NET Framework. In this article, I will introduce you to Caching dependencies.

Caching Dependencies

Caching can depend on several items which include user request, file, database tables, table rows, duration, user controls, query strings, browsers and also other cached items. Let's start with the Caching dependency on other cached items.

Caching Dependency on Cached Items

It is interesting to note that your cached item can depend on other cached items. This means that if the item A is removed from the cache, you can also remove item B from the cache. Let's start by creating and inserting the item A and item B in the Cache object.

C#
protected void Button3_Click(object sender, EventArgs e)
{
    // create item A and item B
    string itemA = "ItemA";
    string itemB = "ItemB";
    Cache.Insert("ItemA", itemA, null, DateTime.Now.AddMinutes(10), 
    TimeSpan.Zero,
    CacheItemPriority.Default, MyItemRemovedCallBack);
    Cache.Insert("ItemB", itemB, null, DateTime.Now.AddMinutes(10), 
    TimeSpan.Zero,
    CacheItemPriority.Default, MyItemRemovedCallBack);
}

In the code above, I am creating two items "itemA" and "itemB". After creating the items, I simply put the items in the Cache object using the Insert method. The last parameter is the callback method "MyItemRemovedCallBack" which will be fired when either of the two items is removed from the Cache.

It is not a good idea to insert the items into the Cache inside the callback method because you might not need the item right away and hence you will be wasting valuable resources to create them.

Let's take a look at the MyItemRemovedCallBack implementation.

C#
private void MyItemRemovedCallBack(string key, object value,
                   CacheItemRemovedReason reason)
{
    // remove the item from the cache
    if (key == "ItemA" ) Cache.Remove("ItemB");
    else if (key.Equals == "ItemB") Cache.Remove("ItemB");
}

The MyItemRemovedCallBack method takes three parameters.

  1. key: This is the key which is used to identify the items in the Cache.
  2. value: The value assigned to the item which is inserted in the Cache.
  3. reason: The variable "reason" is of type CacheItemRemovedReason enumeration and it identifies the reason the item was removed from the Cache.

The code given below removes an item from the Cache and as soon as the item is removed, the "MyItemRemovedCallBack" method is fired and removes the other item from the Cache.

C#
protected void Btn_RemoveCacheItem(object sender, EventArgs e)
{
    Cache.Remove("ItemA");
}

Cache Dependency on a File

Next, let's see the Cache dependency on a file. Making the Cache dependent on the file means that when the file contents changes the Cache is expired and the contents are fetched again. Take a look at the simple XML file below which contains the information about the web site menu.

XML
<?xml version="1.0" encoding="utf-8"?>
<MenuItems>
    <MenuItem>
        <Text>Home</Text>
    </MenuItem>
    <MenuItem>
        <Text>About us</Text>
    </MenuItem>
    <MenuItem>
        <Text>Contact us</Text>
    </MenuItem>
    <MenuItem>
        <Text>Help</Text>
    </MenuItem>
    <MenuItem>
        <Text>Feature</Text>
    </MenuItem>
</MenuItems>

We will use the Cache.Insert method to make the Cache dependent on the file. Take a look at the code below:

C#
private void CreateMenu()
{
    string menuPath = "MyFiles/Menu.xml";
    string folderName = "MyFiles/";

    DataSet ds = null;
    if (Cache["Menu"] == null) 

We will use the Cache.Insert method to make the Cache dependent on the file. Take a look at the code below:

C#
private void CreateMenu()
{
    string menuPath = "MyFiles/Menu.xml";
    string folderName = "MyFiles/";

    DataSet ds = null;
    if (Cache["Menu"] == null)
    {
        ds = new DataSet();
        ds.ReadXml(Server.MapPath(menuPath));

        // menu is created
        Cache.Insert("Menu", ds, new System.Web.Caching.CacheDependency(
            Server.MapPath(menuPath)),DateTime.Now.AddMinutes(60),
            TimeSpan.Zero,
            System.Web.Caching.CacheItemPriority.Default,
            new System.Web.Caching.CacheItemRemovedCallback(
                                  CacheItemRemovedCallBack));

       DisplayCacheCreationTime("Object was not in the cache and created at:",
             DateTime.Now.ToLongTimeString());
    }
    else
    {
        // menu is created from the cache
        DisplayCacheCreationTime("Object was in the cache",String.Empty);
    }
}

The CreateMenu method is responsible for creating the Cache dependency on a file. As, you can see, I have used the DataSet's ReadXML method to read the contents from the XML file and later inserted the DataSet into the Cache. The CacheDependency method is responsible for setting Cache dependent on the file. I have also included an ItemRemovedCallBack callback method which is fired whenever the Cache dependency is expired (in this case whenever the file changes). If you execute the code above the first time, the method CreateMenu is executed it will read the contents from the file since, initially the Cache is empty but for all the later requests the contents are fetched from the Cache object.

You can also create a Cache dependency on the folder. This will mean that whenever a file or a subfolder is added, deleted then the Cache is expired and a new (fresh) copy is fetched.

Cache Dependency on SQL

One of the biggest improvements in ASP.NET 2.0 Caching is the feature of Cache dependency on database tables. This means that the data will be present in the Cache as long as the table entries does not change. As soon as the database table is changed, the Cache is expired. You can enable the SQL Cache dependency by using the aspnet_regsql.exe command line tool. Simply type the following command on the Visual Studio.NET 2005 command line.

aspnet_regsql -ed -E -d School

The command above will enable the Cache dependency on the "School" database. The next step is to enable the caching on the individual table. You can do that by using the following line:

aspnet_regsql -et -E -d School -t Users

The above line will enable the caching on the Users table which is contained in the School database.

The next step is to create the connectionString in the connectionStrings section and sqlCacheDependency in the web.config file. Take a look at the code below:

XML
<connectionStrings>
    <add name="ConnectionString"
         connectionString="Server=localhost;Database=School;
Trusted_Connection=true"/>
</connectionStrings>

<system.web>
    <caching>
        <sqlCacheDependency pollTime="10000" enabled="true" >
            <databases>
                <add connectionStringName="ConnectionString" name="School"/>
            </databases>
        </sqlCacheDependency>
    </caching>lt;/caching>

As, you have noticed that the sqlCacheDependency have a pollTime attribute which is set to "1000" milliseconds. This means that the ASP.NET will check the database table for any changes every 10 seconds. The database section of the <caching> contains the connectionString which is used to connect to the database.

The final step is to use the caching in your code. You can do this in various ways. Take a look at the following code which uses caching programmatically.

C#
private void BindData()
{
    // if null then fetch from the database
    if (Cache["Users"] == null)
    {
        // Create the cache dependency
        SqlCacheDependency dep = new SqlCacheDependency("School", "Users");
        string connectionString = ConfigurationManager.ConnectionStrings[
                                        "ConnectionString"].ConnectionString;
        SqlConnection myConnection = new SqlConnection(connectionString);
        SqlDataAdapter ad = new SqlDataAdapter("SELECT FirstName, LastName " +
                                               "FROM Users", myConnection);
        DataSet ds = new DataSet();
        ad.Fill(ds);

        // put in the cache object
        Cache.Insert("Users", ds, dep);
    }

    gvUsers.DataSource = Cache["Users"] as DataSet;
    gvUsers.DataBind();
}

The line SqlCacheDependency dep = new SqlCacheDependency("School", "Users"); is used to create the caching on the School database and Users table. In the beginning of the BindData method, I check that if the item is already in the Cache. If it is, then I simply return the item using caller by casting it from the Cache object. If the item is not in the Cache, then the data is fetched from the database and inserted into the Cache object. The Cache will be discarded anytime you make a change in the database table "Users". This means that if you INSERT, DELETE, UPDATE any data in any row in the Users table, then the Cache will be considered obsolete and a copy of the fresh data will be fetched from the database.

Caching in SQL Server 2005 has a different architecture then in SQL Server 2000. You don't have to write any lines in web.config to enable Caching in SQL Server 2005. Also, in SQL Server 2005, the Cache is only expired when the row is changed in the database table.

Conclusion

Caching when implemented correctly improves the performance of the application considerably. There is much more to learn in Caching which I will cover in my upcoming articles.

I hope you liked the article, happy coding!

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.