Wednesday, September 27, 2006

Caching in Windows Application

I was working on a Windows Service lately that generated hundreds of documents by processing data retrieved from several database tables. Each time, the service accessed at least 10 lookup tables apart from getting data from various other ones to generate a single document. One thing that concerned me most was its sluggish performance that resulted from its repeated calls to the lookup/reference tables.


I was wondering if there was a way to add caching feature to my windows service, where all the lookup tables are stored locally for a specified duration of time and minimize the overall database calls. You know, caching is one of many such features that are strongly tied to ASP.NET web applications only. Guys at Microsoft encourage you to use Caching Application Block or the latest Enterprise library to enjoy the same features in windows applications.
I stumbled upon a Microsoft Knowledge base article a while ago that suggests using alternative mechanisms such as ASP.NET Cache, 'coz the cache application block had inconsistencies with multithreaded applications. Exceptions occurred when several threads tried to update the cache at the same instance. This got me thinking; why not use the ASP.NET cache in my Windows service application. I'm telling you, this worked like a charm, enjoying the benefits of caching that a ASP.NET web application would provide.
Here's what I did…
I created a new Class Library Project named WinCaching in C#. Added a reference to System.Web.dll. (Convince your Code QA/review team, why you're referencing this namespace from a windows app)
In this class I exposed a public property called Cache which returns the HttpContext.Current.Cache or HttpRuntime.Cache based on the type of application it is. Say, if I'm accessing this property in a WinForms application, the HttpContext.Current.Cache would usually be null, eventually returning the HttpRuntime cache to the caller. The HttpRuntime class provides a bunch of ASP.NET run-time features to the current WinForms or Windows Service applications.
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Caching;

namespace WinCaching
{
    public class Caching
    {

        public static Cache Cache
        {
            get
            {
                return (System.Web.HttpContext.Current == null) ? System.Web.HttpRuntime.Cache : 
System.Web.HttpContext.Current.Cache;
            }
        }
    }
}

All the other classes that needs to use the caching feature in your application will have to do so by accessing this property. I'll show you how…
Create a WinForms application, add a reference to the WinCaching class library that we created above.
To insert data into the cache with expiration time of 60 minutes you can write as
WinCaching.Caching.Cache.Insert("TestKey", txtName.Text, null, DateTime.Now.AddMinutes(60), TimeSpan.Zero);

Similarly, to retrieve the same data, you can access the property as

string s = WinCaching.Caching.Cache["TestKey"].ToString();

This way, you can reuse the same library for your caching needs in Windows as well as Web applications. Hope this trick helps you in improving your application's performance.

2 comments:

maick said...

In case of standalone cache this solution works but when you go to enterprise level it gradually drops performance . This drawback can be overcome by using third party integrations including NCache which is freely available and can be tested for the performance and scalability.
http://www.alachisoft.com/ncache/cab_index.html

ניר said...

Great tip, thanks a lot!