Export (0) Print
Expand All

Creating a Cache Configuration Object for ASP.NET

 

Steven A. Smith
ASPAlliance.com

September 2003

Applies to:
    Microsoft® ASP.NET

Summary: Learn how the CacheConfig helper class can improve caching policies across an ASP.NET application, improve reuse of cached data, and significantly reduce lines-of-code to implement caching using best practices. This article builds upon the ASP.NET Caching: Techniques and Best Practices article. (7 printed pages)

Download CacheConfigDemo.msi.

Contents

Introduction
Configuration
First Use
Primary Method: DeCache
Usage: Adding Cache Support to a Data Access Layer
Summary
Resources

Introduction

If you haven't yet, please read ASP.NET Caching: Techniques and Best Practices. This article builds heavily on the contents of that article, most particularly the best practices. In this article, I will describe the internal makeup of the CacheConfig class, a helper that provides a wrapper for the Cache object found in Microsoft® ASP.NET. This class exposes one very simple method that will do most of the common cache work done within an ASP.NET application. With the CacheConfig class, you will be able to enable or disable caching with the flip of a configuration setting, manage all cache entries and their cache durations via configuration settings, and access the cache using the best practice technique described in the previous article with a single line of code.

Configuration

CacheConfig reads all of its configurable settings from the web.config file. The specific section and each key value within that section are all defined with default values as static strings, as shown in Code Sample 1.

Code Sample 1. Configuration section and key names

protected static string cacheSettingsConfigName = "CacheSettings";
protected static string EnableCachingKey = "EnableCaching";
protected static string RequireKeyDefinitionInConfigKey = 
  "RequireKeyDefinitionInConfig";
protected static string DefaultCacheDurationUnitsKey = 
  "DefaultCacheDurationUnits";
protected static string DefaultCacheDurationValueKey = 
  "DefaultCacheDurationValue";

By default, all of the CacheConfig configuration settings will be stored in a custom configuration section called "CacheSettings". This section is defined as a simple NameValueCollection, just like the built-in AppSettings configuration section. You must define this new configuration section in your web.config as shown in Code Sample 2.

Code Sample 2. Defining the CacheSettings config section within web.config

<configSections>
<section name="CacheSettings" 
  type="System.Configuration.NameValueFileSectionHandler, System, 
  Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
  />
</configSections>

The <configSections> element must be the first element within the configuration element of web.config.

Once this section has been defined in web.config, and the appropriate keys added, it will manage the behavior of the CacheConfig class within your application. Code Sample 3 shows a sample CacheSettings section.

Code Sample 3. CacheSettings keys and values

<CacheSettings>
<!-- true/false -->
<add key="EnableCaching" value="true" />
<!-- true/false -->
<add key="RequireKeyDefinitionInConfig" value="true" />
<!-- seconds, minutes, or hours -->
<add key="DefaultCacheDurationUnits" value="seconds" />
<!-- integer -->
<add key="DefaultCacheDurationValue" value="30" />

<!-- Cache Keys and Durations - 
use "default" for value to use default otherwise integer. -->
<add key="AuthorsDataTable" value="default" />
<add key="AuthorsDataTableByState" value="10" />
</CacheSettings>

The first four keys have the greatest impact on the behavior of CacheConfig. The last keys define the cache key name and cache duration of all objects that are stored in the cache using CacheConfig. The effects of the first configuration values are described in Table 1.

Table 1. Configuration settings and their effects

SettingDescription
EnableCachingTrue/False. When false, CacheConfig is effectively disabled and no entries will be written to or read from the Cache.
RequireKeyDefinitionInConfigTrue/False. When true, will raise an exception if a key is provided to CacheConfig but not found in web.config.
DefaultCacheDurationUnits"seconds", "minutes" or "hours". Defines the units for the duration value specified in the next section. Used as the default cache duration for items added to the cache with no specified time period.
DefaultCacheDurationValue(integer). Specifies the length of time an item should be stored in the cache, using the units defined in DefaultCacheDurationUnits. Used as the default cache duration for items added to the cache with no specified time period.

As this is just a 1.0 version of the CacheConfig class, it is fairly simple. Future enhancements may add support for other kinds of key dependencies, such as files, with the file paths stored in the configuration just as the current settings are stored. For most of my cache usage, I'm caching data coming from Microsoft SQL Server™, so time based caching is sufficient (at least until built-in support for SQL table cache invalidation is available with ASP.NET's cache API).

First Use

CacheConfig is a completely static (shared in Microsoft Visual Basic®) class, which means that it is never directly instantiated. Instead, its methods are used directly. It does, however, have a constructor that is called whenever one of its methods is first invoked. This static constructor performs the following tasks:

  • Loads the CacheSettings configuration section into a local NameValueCollection.
  • Sets the local EnableCaching variable based on configuration settings.
  • Sets the local RequireKeyDefinition variable based on configuration settings.
  • Sets the local DefaultCacheDuration TimeSpan based on configuration settings.
  • Checks to see if an HttpContext (required for caching) is available, and sets EnableCaching to false if not (avoids errors at design time or when a data access layer is called from a windows forms application).

This static constructor is only called once, when CacheConfig is first referenced. However, since all settings are stored in web.config, any updates will result in a complete application restart, which will of course mean that the next call to CacheConfig will once more run the static constructor and retrieve the latest values.

Primary Method: DeCache

The only method I find myself calling is DeCache. DeCache will pull a value out of the cache for a given key. If the value doesn't exist in the cache, DeCache will repopulate the cache using a method provided as a callback, and return the results of this method. CacheConfig can also be used to simply add an item to the cache, using the EnCache() method, but I almost never find the need to use this functionality.

A separate DeCache method must exist for each data type that is to be cached. The 1.0 version of CacheConfig supplied with this article has support for DataTable objects only. This can easily be extended to include additional objects, including System.Object if ultimate flexibility is desired over strong type checking, but doing so requires a lot of duplicate code. Once C# supports generics, a lot of this duplicate code will be avoidable, and I hope to produce a new version of this tool.

The DeCacheDataTable() method supports several overloads:

(string key, GetDataTableCallback callback)—At a minimum, a key and a delegate to populate the cache if it is empty are required.

(string key, GetDataTableCallback callback, object[] callbackArguments)—Includes an array of parameters for the callback method.

(string key, GetDataTableCallback callback, object[] callbackArguments, TimeSpan cacheDuration)—Includes a duration, which will override whatever is specified in the web.config for this key.

(string key, GetDataTableCallback callback, object[] callbackArguments, TimeSpan cacheDuration, bool IgnoreCache)IgnoreCache is treated as false if not present. Setting it to true will force the cache to be bypassed, the value pulled from its original source.

The GetDataTableCallback delegate is defined as:

public delegate DataTable GetDataTableCallback(object[] args);

Since most of the time the existing method for pulling data from the data source doesn't use the signature of (object[] args), what is typically done is to create a new private or protected method with this signature, and call into it from the existing methods. An example of this kind of usage is shown below.

Usage: Adding Cache Support to a Data Access Layer

The downloadable sample application includes a very simple web application with one Web form for listing authors from the Pubs database and one data access class for querying Pubs for these authors. The data access class, Author.cs, uses the Microsoft Data Access Application Block to minimize the amount of code required for its data access. Before adding caching support, it consists of two methods: ListAuthors() and ListAuthors(string state). Each of these returns a DataTable with the contents of the Authors table—the latter one filtered by the value of the state column. The ListAuthors() method, prior to adding cache support, is shown in Code Sample 4.

Code Sample 4. A simple data access method with no caching support

public static DataTable ListAuthors()
{
   return SqlHelper.ExecuteDataset(ConnectionString, 
      CommandType.Text, 
      "SELECT * FROM Authors").Tables[0];
}

Using CacheConfig to add caching support to this method, we must first create a new overload that matches the GetDataTableCalllback delegate's signature, meaning it must return a DataTable and accept an object array as its only parameter. We'll move our actual data access code to this new method, as shown in Code Sample 5.

Code Sample 5. Move the actual data access code to a method matching the delegate.

protected static DataTable ListAuthors(object[] args)
{
   return SqlHelper.ExecuteDataset(ConnectionString,
      CommandType.Text,
      "SELECT * FROM Authors").Tables[0];
}

Once the new method is created, change the original method to use the CacheConfig.DeCache() method and send it a callback referencing the new ListAuthors(object[]) method. Code Sample 6 shows the new version of ListAuthors().

Code Sample 6. ListAuthors(), now modified to include caching support

public static DataTable ListAuthors()
{
   GetDataTableCallback callback = 
new GetDataTableCallback(Author.ListAuthors);
   return CacheConfig.DeCacheDataTable("AuthorsDataTable", 
callback, new SqlParameter[]{null});
}

The sample code provided includes another overload for ListAuthors() to support filtering by state, which shares the use of the protected method by altering the SQL slightly and using the array of parameters sent to it.

Summary

By referencing CacheConfig in your ASP.NET applications and using it for all of the caching operations it supports, you will have greater control over your caching policies and greater confidence that you are referencing the cache using best practice techniques. Although limited to DataTable objects with absolute expirations in its current form, the CacheConfig class is easily extended to encapsulate whatever other types of serializable objects you need to cache, using whatever dependencies you wish to define.

Resources

ASP.NET Caching: Techniques and Best Practices

About the Author

Steven A. Smith, Microsoft ASP.NET MVP, is president and owner of ASPAlliance.com. He is also the owner and head instructor for ASPSmith Ltd, a .NET-focused training company. He has authored two books, the ASP.NET Developer's Cookbook and ASP.NET By Example, as well as articles in MSDN® and AspNetPRO magazines. Steve speaks at several conferences each year and is a member of the INETA speaker's bureau and the ASPInsiders. Steve has a Master's degree in Business Administration and a Bachelor of Science degree in Computer Science Engineering.

Steve can be reached at ssmith@aspalliance.com.

Show:
© 2014 Microsoft