Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

WCF Cache

4.69/5 (16 votes)
10 Dec 2009CPOL4 min read 106.5K   4.1K  
A WCF Service caching example.

caching_enabled_20s.JPG

Introduction

In this article, I’ll discuss caching in WCF services, and I’ll demonstrate how WCF caching can be implemented.

Source Code

The source code contains two Windows applications. The first hosts a demo WCF service. The second application is the WCF demo client. The solution also contains the WCFCache class I wrote that allows you to easily add caching features to WCF services or any other type of application. For running the code, you’ll need the AdventureWorks database that can be downloaded here. Also, you’ll need to update the connection string in the configuration file of the WCF server with the required values.

WCF Caching

Caching in WCF, if used wisely, is definitely a good thing. Lets say that you have a method in your service that executes expensive queries, and this method is called very often, there is a big percentage of calls that pull the same data, the resulting data is not too big to be stored in memory (if, of course, it’s going to be stored in memory), and the data can be considered valid for a period of time, then this is the perfect place to use some sort of caching.

How can caching be added to WCF? You can implement a custom solution like this one, you can use some third party components, or you can use the System.Web.Caching.Cache class. I don’t recommend the last one because I have never tried using it in this context. I found different opinions on the web about this. For me, the fact that Microsoft explicitly recommends not to do it was enough reason not to use it: “The Cache class is not intended for use outside of ASP.NET applications. It was designed and tested for use in ASP.NET to provide caching for Web applications. In other types of applications, such as console applications or Windows Forms applications, ASP.NET caching might not work correctly.” http://msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx.

A typical data access method that uses caching executes the following two general steps: Checks the cache for the existence of the requested data and returns the data if found. If the data is not found in the cache, then it pulls it from the data store, stores it in the cache, and returns the data.

Also, you have to take care of removing or updating data in the cache under certain conditions. Usually, this is done when the data is no longer valid (was changed, or it wasn’t updated for too long), or the data was not used for too long.

Using the WCFCache class

The class was designed to provide similar functionality as System.Web.Caching.Cache. The class is used through its static properties. It allows you to add or remove items from the cache. It has the possibility to indicate item expiration time and/or sliding expiration time. Below are some examples of using the class:

C#
//add/update an item to the cache. No expiration date. No sliding expiration time.
WCFCache.Current[productID] = product;

//add/update an item in the cache.
//The item will expire in 2 minutes. No sliding expiration time.
WCFCache.Current.Insert(productID, product, DateTime.Now.AddMinutes(2));

//add/update an item to the cache. No expiration date. 
//Expiration sliding time is 30 seconds.
WCFCache.Current.Insert(productID, product, new TimeSpan(0, 0, 30), true);

//get an item from the cache
product = (Product)WCFCache.Current[productID]

//change cache refresh frequency. Default value is 20 seconds.
//This means each 20 seconds the cache is inspected for expired items.
WCFCache.Current.CacheRefreshFrequency = new TimeSpan(0,0,10);

Now, let’s discuss a little on how it was implemented. Internally, the data is stored in a hash table for faster access. To make the class thread safe, I used the ReaderWriterLockSlim class. ReaderWriterLockSlim allows multiple threads for reading and exclusive access for writing. Below is how one of the overloaded versions of the Insert method was implemented:

C#
public void Insert(object key, object value)
{
    _itemsLock.EnterWriteLock();
    try
     {
          _items[key] = new WCFCacheItem(value);
      }
      finally
      {
          _itemsLock.ExitWriteLock();
      }
}

where _itemsLock is ReaderWriterLockSlim and _items is the hash table.

For inspecting the cache for expired items, I used System.Threading.Timer.

Code Testing

For the purpose of testing the class, I created a WCF service and WCF client, both in the form of Windows applications. The client creates a number (it’s configurable from the UI) of threads on start. Each thread will pick a random product ID and try to get the data from the server on that product. On the server side, there are two methods exposed. One for getting the initial list of products IDs and another to get data on a particular product. Only the second method uses caching. Caching can be disabled or enabled in the server UI. Also, the sliding expiration time for the created cached items can be specified. Below are the results of running the test for 5 minutes with caching enabled:

caching_enabled_40s.JPG

and caching disabled:

caching_disabled.JPG

As you can see, the average call time with cache enabled was 78 milliseconds, and with cache disabled was 528 milliseconds. If the query for getting the product would run longer, then the difference would be correspondingly bigger.

Conclusion

Thank you for reading. I hope this was useful to you.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)