Easier way to manage your ASP.NET Cache

I was recently told by a client of mine that the ASP.NET app I developed was WAY TOO SLOW! I had to agree; the site was pinging the database twice on every load of the home page. So I said, "Give me a week... I'll make it work better". I went home feeling bad... my app was slow and I really didn't know where to begin. I had a lot of code that depended on pinging the database and I didn't want to sift through it all. What I ended up doing was using the cache object.

I started to look at other open source projects and their approaches to caching. Than DotNetKicks' cache manager caught my eye! I went off that idea and created my own way of implementing an object to interface with the cache object, making it more manageable.

The Cache manager I wrote has 3 methods (Grab, insert, clear), a constructor and 2 properties (CacheKey, CacheDuration). So here's my code in VB and C#:

 

using System.Web;
using System.Web.Caching;
namespace MainSite.Cache
{
  public class CacheManager<T>
  {
    private string m_cachekey = "";
    public string CacheKey {
      get { return m_cachekey; }
      set { m_cachekey = value; }
    }

    private int m_cacheduration;
    public int CacheDuration {
      get { return m_cacheduration; }
      set { m_cacheduration = value; }
    }

    public CacheManager(string Key, int duration)
    {
      this.CacheKey = Key;
      this.CacheDuration = duration;
    }

    public T Grab()
    {
      return (T)HttpContext.Current.Cache(this.CacheKey);
    }

    public void Insert(T obj, System.Web.Caching.CacheItemPriority priority)
    {
      DateTime expiration = DateTime.Now.AddMinutes(this.CacheDuration);
      HttpContext.Current.Cache.Add(this.CacheKey, obj, null, expiration, TimeSpan.Zero, priority, null);
    }

    public void Clear()
    {
      HttpContext.Current.Cache.Remove(this.CacheKey);
    }

  }
}

Imports System.Web
Imports System.Web.Caching

Namespace MainSite.Cache
    Public Class CacheManager(Of T)

        Private m_cachekey As String = ""
        Public Property CacheKey() As String
            Get
                Return m_cachekey
            End Get
            Set(ByVal value As String)
                m_cachekey = value
            End Set
        End Property

        Private m_cacheduration As Integer
        Public Property CacheDuration() As Integer
            Get
                Return m_cacheduration
            End Get
            Set(ByVal value As Integer)
                m_cacheduration = value
            End Set
        End Property

        Public Sub New(ByVal Key As String, ByVal duration As Integer)
            CacheKey() = Key
            CacheDuration() = duration
        End Sub

        Public Function Grab() As T
            Return CType(HttpContext.Current.Cache(CacheKey()), T)
        End Function

        Public Sub Insert(ByVal obj As T, ByVal priority As System.Web.Caching.CacheItemPriority)
            Dim expiration As DateTime = DateTime.Now.AddMinutes(CacheDuration())
            HttpContext.Current.Cache.Add(CacheKey(), obj, Nothing, expiration, TimeSpan.Zero, priority, Nothing)
        End Sub

        Public Sub Clear()
            HttpContext.Current.Cache.Remove(CacheKey())
        End Sub

    End Class
End Namespace

 

So what I do is create a class and have a grab method that makes an instance of the cache manager object and calls the cache manager class' grab method. If the cache returns null, I have a private method in my class that does the nesessary things to put the info into the cache object. Here's an example:

namespace MainSite.Cache
{
  public class ReviewsCache
  {
    public static ReviewsCollection Grab()
    {
      CacheManager<ReviewsCollection> man = new CacheManager<ReviewsCollection>(GetKey(), 90);

      ReviewsCollection cont = man.Grab();

      if (cont == null) cont = Insert(man); 

      return cont;
    }

    private static ReviewsCollection Insert(CacheManager<ReviewsCollection> man)
    {
      ReviewsCollection cont = MainSite.Logic.Reviews.GetAll();
      man.Insert(cont, Web.Caching.CacheItemPriority.Default);
      return cont;
    }

    public static void Delete(string sectionname)
    {
      CacheManager<ReviewsCollection> man = new CacheManager<ReviewsCollection>(GetKey(), 90);
      man.Clear();
    }

    private static string GetKey()
    {
      return "Reviews";
    }

  }
}
Namespace MainSite.Cache
    Public Class ReviewsCache

        Public Shared Function Grab() As ReviewsCollection
            Dim man As New CacheManager(Of ReviewsCollection)(GetKey(), 90)

            Dim cont As ReviewsCollection = man.Grab()

            If cont Is Nothing Then cont = Insert(man)

            Return cont
        End Function

        Private Shared Function Insert(ByVal man As CacheManager(Of ReviewsCollection)) As ReviewsCollection
            Dim cont As ReviewsCollection = MainSite.Logic.Reviews.GetAll()
            man.Insert(cont, Web.Caching.CacheItemPriority.Default)
            Return cont
        End Function

        Public Shared Sub Delete(ByVal sectionname As String)
            Dim man As New CacheManager(Of ReviewsCollection)(GetKey(), 90)
            man.Clear()
        End Sub

        Private Shared Function GetKey() As String
            Return "Reviews"
        End Function

    End Class
End Namespace

 

The cache object is a great thing to utilize in ASP.NET. But to make the caching manageable, you need to have a structure for managing the cache object and add logic to delete, grab, etc. Interfacing with a class is easier and follows the MVC pattern better than just saying Cache["MyKey"] in your logic or UI.



kick it on DotNetKicks.com
Published Saturday, October 20, 2007 2:11 PM by zowens
Filed under: , , ,

Comments

# re: Easier way to manage your ASP.NET Cache

WTF does your code have to do with MVC?  It looks like Identity Map to me.

Saturday, October 20, 2007 2:20 PM by Joe Chung

# re: Easier way to manage your ASP.NET Cache

Joe,

It had a model (CacheManager) and controllers that use the CacheManager. It's sorta like MVC... not really... but I like to think of it that way.

Saturday, October 20, 2007 7:54 PM by zowens

# re: Easier way to manage your ASP.NET Cache

This has potential in-rush issues in a web farm scenerio. Refactoring your ReviewCache class to use locks and class variables would solve the problem.

Sunday, October 21, 2007 9:12 AM by Chuck Conway

# re: Easier way to manage your ASP.NET Cache

@Chuck

Yea... in my clients site, I did use locks. I wanted to keep it simple for this blog post though.

Sunday, October 21, 2007 10:48 AM by zowens

# re: Easier way to manage your ASP.NET Cache

The biggest problem with cache usage is indeed that when using webfarms you can not store user dependant data. It actually should never store such information. However it can be very usefull in lots of other cases to increase performance drastically.

A second note: I agree with Joe. This manager has nothing to do with MVC. Yes, you can use it in a MVC application, but let's be fair, you can use about a lot of stuff inside a mvc application...

Sunday, October 21, 2007 4:11 PM by JV

# re: Easier way to manage your ASP.NET Cache

OK... who uses a webfarm other than enterprises? MOST people use a shared or 1 dedicates/virtual server. The Cache object is optimal for those people. If you want a webfarm sort of caching scenario, USE ENTERPRISE LIBRARY!

I KNOW THIS HAS NOTHING TO DO WITH MVC!!! BUT THIS FOLLOWS THE PATTERN LOOSLY! I should have chosen my words better... whatever... give it a rest people.

Sunday, October 21, 2007 5:30 PM by zowens

# re: Easier way to manage your ASP.NET Cache

Don't get me wrong Zack. Your manager is definatly very valuable for cache abstraction. I actually use a very similair implementation for it.

Sunday, October 21, 2007 6:03 PM by JV

# re: Easier way to manage your ASP.NET Cache

Hey um, give the dude a break already!  I don't know this guy from Adam, but it's pretty clear he's trying to help people out with the fruit of his labor, no need to get all Britney Spears catty on him over scenarios he never claimed to address or semantics.  I'm sure this code is very useful for some folks and a good starting place for others.

Keep it up man.  

Monday, October 22, 2007 1:44 PM by Mike Duncan

# re: Easier way to manage your ASP.NET Cache

I have to agree with Mike. There are way too many people who read blogs just to blast whatever the author puts on up in an effort to assist. I wish there was  way to enforce the old saying; "If you don't have anything good to say, then just do say anything". Just my 2 cents.

Monday, October 22, 2007 3:15 PM by Dennis

# re: Easier way to manage your ASP.NET Cache

Is this from Gavin or Zack? Anyways, I like the wrapper, but I'd prefer a more OO approach, with interfaces and implementors, it would be cleaner.

Monday, October 22, 2007 6:02 PM by Simone Busoli

# re: Easier way to manage your ASP.NET Cache

@Simone

This would be written by me, inspired from Gavin.

I could have use interfaces... but we should keep it simple!

Monday, October 22, 2007 6:06 PM by zowens

# re: Easier way to manage your ASP.NET Cache

Great article.  I stumbled on it after impl'ing my own and realizing that someone has probably already done this.  I added one nicety to mine that I don't see here.  A delegate called "OnGetNewData" for the cachemgr that will fire when the internal cache returns NULL for a lookup.  This allows the caller to subscribe to the event and handle the actual datafetch, then return back to the cachemgr for proper storage.

Saturday, January 5, 2008 1:35 PM by Shawn

# re: Easier way to manage your ASP.NET Cache

Zach.  I know where you are coming from.  You learn something new,  create a class to make integration easy, then you tell the world about it.  Only to have people tell you that its old stuff.  You have good intentions.  Keep it up!  I remembered when I discovered the asp.net Cache Object.  It was like I discovered a new religion, very exciting times.  Your coding skills are a bit advanced to mine.  I tend to just stick to simple functions.  Here is how I do stuff in my helper functions.

<pre><code>

// add item to cache

public void addToCache(string cachename, string data, int hours){

Cache.Insert(cachename, data, null, DateTime.Now.AddHours(hours), System.Web.Caching.Cache.NoSlidingExpiration);

}

// get item from cache

public string getFromCache(string cachename){

return (string)Cache[cachename];

}

// in action with another helper function

public string getBlogName(string blogid){

string cachename="getBlogName_"+blogid;

if(getFromCache(cachename)!=null){return getFromCache(cachename);}

string data=countDB3("SELECT title FROM blogs where id='"+blogid+"'");

addToCache(cachename, data, 12);

return data;

}

</code></pre>

Friday, June 27, 2008 1:58 AM by WhiteSites

# re: Easier way to manage your ASP.NET Cache

This was EXTREMELY helpful to me today!

Wednesday, September 24, 2008 4:43 PM by Dave Neeley

# re: Easier way to manage your ASP.NET Cache

@Dave

YAY! That's awesome!

Wednesday, September 24, 2008 4:52 PM by Zack

# re: Easier way to manage your ASP.NET Cache

Hi Zack,

Congrats for such an informative article. I too have a blog regarding ASP.NET Cache, it various uses, limitations and how to fix them. You are absolutely correct. Caching is an awesome way of speeding up apps.

Monday, September 29, 2008 12:56 PM by Paul Jones

# re: Easier way to manage your ASP.NET Cache

This is a concise, informative article.  It turned up in my search for Cache information and convinced me to implement such a class in my project.  I'll be editing it somewhat to give the option of passing a CacheDependency object.  Thanks for sharing!

Wednesday, October 22, 2008 4:39 PM by Code Dependent

# re: Easier way to manage your ASP.NET Cache

Hi Zack!

Nice post.

I must point out however that ASP.NET Cache has some very intrinsic problems. Its not scalable for large server farms and its In-Process nature isn't reliable either.The right way to solve this scalability problem is through an in-memory distributed cache.

Microsoft is finally realizing it. They're working on Velocity but that is still in its infancy and will take some time to stabilize and mature.

Wednesday, October 29, 2008 12:29 PM by Sarah on ASP.NET Cache

# re: Easier way to manage your ASP.NET Cache

Thanks for the awesome code sample!

I found one minor thing wrong with your C# example - you have to use brackets and not parens for accessing the cache like "HttpContext.Current.Cache[this.CacheKey]" instead of "HttpContext.Current.Cache(this.CacheKey)".

Also, I was getting some NullReferenceExceptions in that method, so I modified it like so and it works nicely:

  public T Grab()

  {

     T temp;

     try

     {

        temp = (T)HttpContext.Current.Cache[this.CacheKey];

     }

     catch (NullReferenceException)

     {

        temp = default(T);

     }

        return temp;

  }

Wednesday, November 26, 2008 3:47 PM by Eric

# re: Easier way to manage your ASP.NET Cache

@Eric

Yea... i was converting from VB to C# and didn't catch that. I'm not that much of a noob anymore :)

I disagree with you on the NullReferenceException. If the value is null in the cache, why return something? The manager class is just an API that delegates the functionality of the HttpCache.

Wednesday, November 26, 2008 4:25 PM by zowens

# re: Easier way to manage your ASP.NET Cache

Well, you can feel free to disagree, but I had to do something because the exception was crashing my app :)  For me this works, as I can test for the returned value safely now...

Wednesday, November 26, 2008 8:33 PM by Eric

# re: Easier way to manage your ASP.NET Cache

@Eric

Just sayin that its not necessarily wrong to return null. Guess its a choice rather a black and white situation.

Wednesday, November 26, 2008 9:12 PM by Zack Owens

# re: Easier way to manage your ASP.NET Cache

Nice one Zack, fits what I needed to a T :)

Wednesday, March 11, 2009 6:05 AM by Mordy

# re: Easier way to manage your ASP.NET Cache

You put this here, so we could use it right?  do you require any credit if we just copy/paste?

Tuesday, January 12, 2010 4:22 PM by ac

# re: Easier way to manage your ASP.NET Cache

Naw, go ahead and copy paste. Code is "as is", so if it breaks I'm not liable :) But other than that, have at it!

Tuesday, January 12, 2010 4:56 PM by zowens

# re: Easier way to manage your ASP.NET Cache

Thanks for posting Zack. Simple and effective.

Saturday, May 1, 2010 12:24 AM by Ben

# re: Easier way to manage your ASP.NET Cache

Here is also a nice post on how to clear cache in asp.net in few line. For more details please check out this link...

mindstick.com/.../Clearing%20Cache%20in%20Asp%20net

Thanks!!

Saturday, November 12, 2011 6:53 AM by gotibandhu