Caching with .NET--when to buy, when to build

.NET introduces some out-of-the-box caching functionality, but of course, you may want or need to write your own caches. Take a walk through the basics of .NET caching in this article.

Smart developers live by the “buy before build” philosophy, but when it comes to improving data retrieval performance via a cache, build has been the only available option. Enter .NET’s Cache class, which adds some typical caching functionality to Microsoft’s out-of-the-box toolset.

While the Cache class can save you time in some development scenarios, it does have first-generation drawbacks—it’s limited to a string key type, for example. But in the right situations, it can be a time-saver. In this article, I’ll describe how to use .NET’s built-in cache and give you a walk-through of how to build your own, when necessary.

Caching basics
A cache is a high-speed storage mechanism used to store frequently used pieces of information. The purpose of a cache is to improve performance. For example, if you are developing an ASP.NET application where many users require the same product list, it makes sense to cache the product list. This approach prevents your application from repeatedly reading information from the database, which may prove slow and hence decrease performance.

.NET’s out-of-the-box caching
The .NET framework exposes a class named Cache, which resides in the System.Web.Caching namespace. Every Web Form object in an ASP.NET application has an object property named cache of type System.Web.Caching.Cache. This object exposes a default parameterized property named item. The item property accepts a string parameter (key) that identifies the object being inserted or extracted from the collection. This key is of utmost importance because it defines the cache data. In the following example, the key “Alphabet” identifies a long string that will be placed into the cache. The application uses the key value to retrieve the long string from the cache.
MyClass.cache.item(“Alphabet”) = s

Remember that MyClass, in this case, represents a Web Form object.

As you can see in this example, the Cache object has a property named item. This property is the object’s default property and so can be omitted from explicit references in the code. However, this can be a hazardous coding practice. Click here for a few pointers on using the default property behavior in your code.

If we want to take the quick route, we can abbreviate the above code to read:
MyClass.cache(“Alphabet”) = s

The compiler interprets this code by simply appending the default property, based on the class type definition’s “Default” keyword.

Once the string is placed into the cache, you can easily extract it using the following code:
Dim s as String
s= MyClass.cache.item(“Alphabet”)

Or, if you choose to omit the default property, you can abbreviate the code to:
s = MyClass.cache (“Alphabet”)

If you want to use caching outside the Web form, you can create a new instance of the Cache object. If you are using the Release to Manufacturing or Commercial Release (RTM) of Visual Studio.NET, you may find some errors using this object. The following code should get you started:
Dim c as System.Web.Caching.Cache
c = new System.Web.Caching.Cache()

After creating an instance of the cache, you‘d use the Insert or Add methods to populate it. Then, you can use the Get method to retrieve the object from the cache.

Building your own cache
Perhaps you fear that Microsoft’s Cache object has so much built-in functionality that it may result in decreased performance. Or perhaps you need a cache that allows the key to be of a type other than a string. (This limitation is a significant drawback of the System.Web.Caching object.) Or perhaps you are simply curious and want to experiment.

Regardless of the cause, sometimes you’ll just want to create your own .NET cache. Let’s take a look at how to create a primitive cache object that can store values. In a subsequent article, we’ll expand this basic cache to include purging facilities through the creation of a background thread.

To build your own cache, you need to understand the concept behind the HashTable object. The HashTable is a collections object located in the System.Collections namespace. Conceptually, the object behaves much like a filing cabinet. You can place objects into a filing cabinet as long as you provide an identifier allowing them to be easily retrieved. This identifier is called the key. The Hashtable object allows object insertion and retrieval.

Now, we will define a new class called CustomCache that uses a private HashTable to store objects put in the cache. CustomCache will expose two methods a subroutine named insertCachedObject and a function named getCachedObject. The insert method will take two parameters a key and an object, while the getCachedObject will take one parameter, a key (see Listing A).

The CustomCache object defined in Listing A requires the client code to create an instance of the CustomCache object prior to using it. If you wanted a cache following a Singleton pattern, meaning that all client code would use the same instance of the cache, then you’d change the object as shown in Listing B.

Notice the addition of the Shared keyword in front of the Hashtable declaration in Listing B, as well as the methods and the constructor. We added a second private constructor to prevent client code from creating an instance of the CustomCache object. All client code will now share a class level HashTable without having to create an instance of CustomCache. The Shared keyword performs the same function as the static keyword in Java; a .NET shared constructor is the same as a Static block in Java.

The example in Listing C is a command-line program that uses the CustomCache to store and retrieve a long Alphabet String.

Our simple cache is now complete. It provides no facility to automatically expire items from the cache after a certain period of time; nor does it provide any means to keep track of least recently used objects, caching hits, and other usage data. But it’s a starting point. In future articles, we’ll expand this code for discussions of threading, delegates, memory management, and other .NET caching issues.

Editor's Picks