Channels ▼
RSS

.NET

Creating a Custom Output Cache Provider in ASP.NET 4


The performance of ASP.NET applications is a serious concern for Web application developers. There have been many improvements, though. The newer versions of .NET Framework have been optimized a lot. Added to all this, you have IIS improvements — better support for application pools, IIS compression, etc. However, we still use cache as a state management technique for storing relatively stable data. In doing so, redundant hits to databases are reduced and the application works faster. Proper usage of caching cuts down on network traffic and ensures that applications are more responsive.

The ASP.NET Caching Framework opens the door for aggressive output caching: It allows you to extend the default cache model and build your own cache providers. In this article, I discuss the basics of cache state management in ASP.NET and how to extend the ASP.NET Caching Framework to implement your own custom caching framework.

To work with the code examples in this article, you should have either Visual Studio 2010 or Visual Studio 11 installed on your system. As of this writing, the Developer Preview Version of Visual Studio 11 is available for free download. The release date of Microsoft Visual Studio 11 has not yet been announced.

Caching: The Basics

Caching is a state management technique that optimizes your application's performance by enabling you to store relatively stable objects in memory and use them as needed without having to access the database or your file system to fetch the same data. If the data in your data store changes, you still can take advantage of cache dependency to ensure that data in the data store synchronizes with that in the memory. MSDN states: "Caching enables you to store data in memory for rapid access. When the data is accessed again, applications can get the data from the cache instead of retrieving it from the original source. This can improve performance and scalability. In addition, caching makes data available when the data source is temporarily unavailable."

Types of Caching in ASP.NET

There are three types of caching in ASP.NET:

  • Page Output Caching — The output of the Web page is stored in cache so that the next requests for the same page can be fetched directly from the cache rather than having to reload it again.
  • Page Fragment or Partial Page Caching — As the names suggests, only fragments or portions of a Web page are cached.
  • Data Caching — you can make use of the Cache API to store the frequently used objects of your application in the cache. So, the processing time of recreating such objects is eliminated.

Implementing Your Own Custom Cache Provider in ASP.NET

It should be noted that CPU and memory are finite resources. In earlier versions of ASP.NET, you were limited to using the default caching mechanism. That is, you did not have any control or any way to extend and build your own cache providers. ASP.NET 4 provides support for cache extensibility through its provider model. Why do we need this extensibility anyway? The most important benefit that you get from implementing your own cache provider is that you can have objects in the cache stored outside of the ASP.NET Worker Process.

Custom cache providers enable caching of data from various data stores that include disks, cloud storage, and distributed cache engines.

Microsoft documentation states: "The ASP.NET output cache uses an in-memory storage mechanism and, until the .NET Framework 4, it wasn't possible to override or replace the default cache with your own implementation. With the new OutputCacheProvider type, it's now possible to implement your own mechanism for caching page output in ASP.NET."

Here's how you can specify output caching in an ASP.NET Web page:

<%@ OutputCache 
    Duration="Specify duration to cache in milliseconds"          
    Location="Any" VaryByParam="None" %>

You have quite a few vary parameters to choose from: VaryByParam, VaryByHeader, VaryByCustom, VaryByControl, and VaryByContentEncoding.

In his blog on this topic, Scott Guthrie states: "ASP.NET 4 adds an extensibility point to output caching that now enables developers to configure one or more custom output-cache providers. Output-cache providers can use any storage mechanism to persist output cached content. This makes it possible to easily create output-cache providers that store the cached content using any persistence mechanism — including local or remote disks, databases, cloud storage, and distributed cache engines (like memcached or Velocity)."

To implement your own custom cache provider class, you need to extend the OutputCacheProvider abstract class of the System.Web.Caching namespace:

public abstract class OutputCacheProvider : ProviderBase

The OutputCacheProvider class contains several abstract methods that you can override to implement your version of custom cache provider. These methods include the following:

  • Add() — This method is used to add an item to the cache
  • Get() — This method is used to retrieve an item from the cache
  • Remove() — Used to remove an item from the cache
  • Set() — This method is used to update an item previously added to the cache

Here is how the OutputCacheProvider class looks:

public abstract class OutputCacheProvider : ProviderBase
 {
   public abstract object Get(string key);
   public abstract object Add(string key, object entry, DateTime utcExpiry);
   public abstract void Set(string key, object entry, DateTime utcExpiry);
   public abstract void Remove(string key);
 }

To implement your own custom cache provider, override the methods of the OutputCacheProvider just shown. It should be noted that custom cache providers support only absolute cache expiration — there is no support for sliding expiration. It should also be mentioned here that cache expiration policies can be of two types: file-based and time-based. Also, if you have multiple cache providers available, you can allow your application to select any among them at runtime depending on the application's needs and the configuration set in the application's configuration file.

The System.Web.Caching namespace contains several classes, interfaces, and enumerations that help to manage your cached objects. You can find more information on the System.Web.Caching namespace at the Microsoft site.

With .NET 4, you can leverage caching in ASP.NET, Windows Forms, and WPF applications. The System.RunTime.Caching namespace has been enhanced a lot to facilitate this. You now can use MemoryCache and your application can have multiple MemoryCache instances at a given point in time. You can retrieve a reference to ObjectCache using the following statement:

static readonly ObjectCache Cache = MemoryCache.Default;

Next, you can add, remove, or edit your objects in the cache. The code sample below illustrates how you can store your objects using the reference you just created:

public static void Add(object obj, string key)
{
     Cache.Add(key, obj, DateTime.Now.AddDays(90));
}


The types in the System.Runtime.Caching namespace now provide support for caching in any application that runs on top of the .NET Framework — not just ASP.NET. A great feature indeed!

In the next section, I'll discuss how we can leverage the cache extensibility feature in ASP.NET to implement the custom cache provider class.

The CustomCacheProvider Class

Our CustomCacheProvider class extends the abstract OutputCacheProvider class.

public class CustomCacheProvider : OutputCacheProvider
{
        
}

The following code listing illustrates our CacheItem class:

using System;

namespace DDJ.Caching
{
    [Serializable]
    internal class CacheItem
    {
        public string Key { get; set; }
        public byte[] Data { get; set; }
        public DateTime Expiration { get; set; }
    }
}

Implementing the Methods of the CustomCacheProvider Class

At first glance, here's how our CustomCacheProvider class looks:

using System.Web.Caching;
namespace DDJ.Caching
{
    public class CustomCacheProvider : OutputCacheProvider
    {
        public override object Add(string key, object entry, 
                                   System.DateTime utcExpiry)
        {
            throw new System.NotImplementedException();
        }

        public override object Get(string key)
        {
            throw new System.NotImplementedException();
        }

        public override void Remove(string key)
        {
            throw new System.NotImplementedException();
        }

        public override void Set(string key, object entry, System.DateTime utcExpiry)
        {
            throw new System.NotImplementedException();
        }
    }
}

The next step is to save your cached data to a persistent storage device, like a database or a file in the file system. There are plenty of articles available that discuss how you can write code to achieve this, so I'll skip this discussion here.

public void Save(CacheItem item, string key)
{
     // Write your custom code here to save your cached item to 
     // a persistent storage device.
}

Now, your CustomCacheProvider class looks like this:

using System.Web.Caching;
using System.Collections.Generic;

namespace DDJ.Caching
{
    public class CustomCacheProvider : OutputCacheProvider
    {
        // Implement the Overriden methods of the OutputCacheProvider class here.

        public void Save(CacheItem item, string key)
        {
            // Write your custom code here to save your cached item to 
            // a persistent storage device.
        }
    }
}

Now that your CustomCacheProvider class is ready, the next step is to configure the cache provider. The next section discusses how to do this.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video