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.