Click here to Skip to main content
6,594,932 members and growing! (15,075 online)
Email Password   helpLost your password?
Web Development » Caching » General     Intermediate License: The Code Project Open License (CPOL)

Data Caching

By Dmitry Zubrilin

Unified algorithm for caching data retrieved from a backend repository.
C# (C# 2.0), .NET, ASP.NET, Dev
Posted:21 Jul 2008
Updated:2 Nov 2008
Views:14,582
Bookmarked:45 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
14 votes for this article.
Popularity: 4.73 Rating: 4.13 out of 5
1 vote, 7.1%
1
1 vote, 7.1%
2

3

4
12 votes, 85.7%
5

Introduction

Data retrieving from a repository can be quite a “heavy” task from a performance point of view, especially when the data repository is located far from the application server (e.g., web service call, RPC call, Remoting etc.) or some specific data is accessed very often. So, in order to reduce the workload and time for data retrieving, you can use a caching functionality.

There are some rules that you should be aware of:

  1. Use caching of data for a small period of time and avoid caching for the whole application lifecycle.
  2. Try to cache the data that is likely to not be changed very often (e.g., dictionary elements).
  3. Some data repositories can support notification events if the data is modified outside of the application (e.g., the data is just stored in a file).

Besides the obvious goals, data caching has some pitfalls (all of them are about potential situations when cached data can expire and application uses inconsistent data):

  1. If the application is going to be scaled to a distributed environment (web farm, application cluster), then every machine will have its own copy of cached data. So, one of the machines can modify the data at any time.
  2. Several applications can access the same data repository.

There are very many different implementations of the caching functionality, but all of them have a lot in common. I will use the “Microsoft Enterprise Library Caching Application Block” and will present you a way of simplifying the usage of the caching functionality.

My implementation of the caching functionality can be divided into two main parts: the cache manager utility and its usage. It heavily uses anonymous methods and generic methods (new features of .NET 2.0).

CacheService is a manager utility that is implemented as a singleton wrapper for underlying the MS caching API. It grants a few methods (GetData<t>, Add, Remove).

Here is the implementation of the caching manager utility:

public delegate T GetCachedObjectDelegate<T><t>();

public sealed class CacheService
{
    #region singletone
    private static CacheService instance;
    private static readonly object instanceSync = new object();
    public static CacheService Current
    {
        get
        {
            if (CacheService.instance == null)
            {
                lock (CacheService.instanceSync)
                {
                    if (CacheService.instance == null)
                    {
                        CacheService.instance = new CacheService();
                    }
                }
            }
            return CacheService.instance;
        }
    }
    private CacheService()
    {
        this.cache = Microsoft.Practices.EnterpriseLibrary.Caching.CacheFactory
            .GetCacheManager();
    }
    #endregion singletone

    private Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager cache;

    public T GetData<T><t>(
            string key, object syncLock,
            TimeSpan timeout, GetCachedObjectDelegate<T><t> getCachedObject
        )
    {
        return this.GetData<t>(key, syncLock, null, timeout, getCachedObject);
    }
    public T GetData<t><T>(
            string key, object syncLock, 
            ICacheItemRefreshAction refreshAction,
            TimeSpan timeout, GetCachedObjectDelegate<T><t> getCachedObject)
    {
        object result = this.cache.GetData(key);
        if (result == null)
        {
            lock (syncLock)
            {
                result = this.cache.GetData(key);
                if (result == null)
                {
                    result = getCachedObject();
                    this.cache.Add(
                     key,
                     result,
                     CacheItemPriority.Normal,
                     refreshAction,
                     new SlidingTime(timeout)
                );
            }
        }
        return (T)result;
    }
    public void Add(
            string key, object value, 
            CacheItemPriority scavengingPriority, 
            ICacheItemRefreshAction refreshAction, 
            params ICacheItemExpiration[] expirations)
    {
        this.cache.Add(key, value, scavengingPriority, refreshAction, expirations);
    }
    public void Remove(string key)
    {
        this.cache.Remove(key);
    }
}

As you can see, this manager class does the following:

  1. It hides all the knowledge about the MS Caching Application Block.
  2. It presents very intuitive methods for working with the caching functionality.

Here is a sample usage:

private const string GET_GOOD_INFO_BY_ID = 
        "GoodService.GoodInfo.GET_GOOD_INFO_BY_ID_";
private const double GET_GOOD_INFO_BY_ID_CACHE_INTERVAL = 0.2 * 60;
private static readonly object GET_GOOD_INFO_BY_ID_SINC_KEY = new object();

public GoodInfoModel GetGoodInfoByID(Guid id)
{
    string key = String.Concat(GoodService.GET_GOOD_INFO_BY_ID, id.ToString());
    return CacheService.Current.GetData<goodinfomodel>(
        key,
        GoodService.GET_GOOD_INFO_BY_ID_SINC_KEY,
        TimeSpan.FromSeconds(GoodService.GET_GOOD_INFO_BY_ID_CACHE_INTERVAL),
        delegate
        {
            return GoodDAL.GetGoodInfoByID(id);
        }
    );
}

As you can see, the usage of the caching functionality is quite simple. And, you can use any appropriate code in your application architecture inside the anonymous method so that it would be easy to add caching support to your application.

All you need is:

  1. Declare a synchronization object that will be used to synchronize access for the cached data;
  2. Define an expiration timeout;
  3. Use an anonymous method that must match the GetCachedObjectDelegate (remember that anonymous methods can access all the variables that are available in its outer method; actually, the C# compiler creates a new class definition that has all the variables as fields, and both the methods are just instance methods).

This implementation of the caching functionality can also be used for application scope caching. But, with a little effort, it can spawn the functionality for caching data at session or request scope.

License

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

About the Author

Dmitry Zubrilin


Member

Occupation: Software Developer (Senior)
Location: Russian Federation Russian Federation

Other popular Caching articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 11 of 11 (Total in Forum: 11) (Refresh)FirstPrevNext
GeneralSQL Cache Pinmemberpradeepvp123458:35 26 Mar '09  
GeneralRe: SQL Cache PinmemberDmitry Zubrilin15:08 26 Mar '09  
GeneralNot scallable PinmemberMileta Cekovic10:13 4 Nov '08  
GeneralRe: Not scallable PinmemberDmitry Zubrilin10:40 4 Nov '08  
Generalimplement cache PinmemberMojtaba Vali19:18 2 Nov '08  
GeneralRe: implement cache Pinmembergil6660:00 3 Nov '08  
GeneralRe: implement cache PinmemberDmitry Zubrilin1:04 3 Nov '08  
GeneralRe: implement cache Pinmembergil6662:28 3 Nov '08  
GeneralRe: implement cache [modified] PinmemberDmitry Zubrilin1:02 3 Nov '08  
GeneralRe: implement cache Pinmembergil6662:50 3 Nov '08  
GeneralPlease Help [modified] Pinmembergil6667:00 2 Nov '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 2 Nov 2008
Editor: Smitha Vijayan
Copyright 2008 by Dmitry Zubrilin
Everything else Copyright © CodeProject, 1999-2009
Web15 | Advertise on the Code Project