Crafting Your Caching Layer

Stop using a caching API directly; step up to a provider-based model in your ASP.NET apps

Scalability became of interest to developers with the advent of the web and heavy server-side web applications. I'm not straying far from the truth when I say that scalability and the advent of ASP.NET development are related. One tool developers have to satisfy the need for scalability is caching. Caching in ASP.NET is provided by a very powerful object—the Cache object. The Cache object provides dictionary-based data entry, data scavenging, notification, removal callbacks, and rich policies for expiring items. But it has one huge limitation—it doesn’t work very well in web farms. More precisely, it works but every machine ends up with its own copy of the data with no guarantee of synchronization. You can certainly do some work to achieve the minimum level of synchronization you need, but in the end you’re left alone with it.

The bottom line is that the Cache object is powerful but inherently limited to a single process. What if you need to use it in a web farm or you need to scale the caching tier across a cluster of machines? In both cases, the Cache object isn’t for you. You can switch to AppFabric Caching Services, which is the Microsoft version of a distributed cache, or you can use another API such as memcached, sharedmem, or commercial products.

Whichever way you look at it, you need to address a fundamental point. Are you going to stick to the same caching solution or is your code the kind that might support different caches in different scenarios? Also, are you going to test your cache-enabled code extensively? To properly address these points, you need to stop using the cache directly—whether it's the native Cache object, the new MemoryCache object in the .NET Framework 4, or a third-party cache. For extensibility and testability reasons, the caching layer in your ASP.NET (and ASP.NET MVC) applications should be based on a provider model or be IoC-enabled. Let’s see how to proceed.

Abstracting the Caching Layer

The idea is to define an abstract interface for the caching layer and then use an internal component (i.e., a provider) to actually do the job of storing and retrieving data. Once you have the interface (or base class) in place you can choose how to inject the actual provider in the real code. The provider can be derived from the ASP.NET native ProviderBase class and use your own factory code. As an alternative it can be based on the IoC tool of choice and initialized according to the rules and syntax of the IoC. Any approach is fine; if I were using this in ASP.NET Web Forms I’d probably use a classic provider. In the context of an ASP.NET MVC application, I’d likely be more comfortable using Unity or another IoC framework. The following code shows a very minimal example of how to abstract the caching layer:

public interface ICacheService


    Object Get(String key);

    void Set(String key, Object data);     Object this[String key] { get; set; }



You're responsible for making this interface as rich and sophisticated as you need. For example, you might want to add members to support dependencies, expiration, and priorities. Just keep in mind that you're not writing the caching layer for the entire ASP.NET subsystem, but simply writing a segment of your application. In this respect, the YAGNI principle (You Aren’t Gonna Need It) holds truer than ever.

The next step consists of picking up a concrete implementation of this interface. In global.asax (Web Forms) or in the controller’s factory (ASP.NET MVC) you can inject a concrete type instance for ICacheService. The concrete type will simply use a particular cache technology to store and retrieve data. Figure 1 shows a skeleton of a class that implements the interface using the native ASP.NET Cache object.

Abstracting the caching layer always improves the quality of your design. It's also a design aspect that is quite cheap to set up, as far as implementation is concerned. The real point is how many features you put in the interface. Simply creating a wrapper is cheap and effective. In summary, as emphatic as it might sound, you should never use the Cache object directly from code-behind classes and controllers in a well-designed, ASP.NET-based layered solution.

Benefits of a Cache Wrapper

Having a provider-based caching layer allows you to reuse parts of the business or data access layer across various applications—for example, the web application and a Windows service. If you use the Cache object directly, you need to spin up the entire web application, even from the context of another type of application. If you use a wrapper, you just create an ad hoc provider and make your code open to extensions but closed to changes.

For example, you can have a cache provider based on AppFabric Caching Services or perhaps the new .NET Framework ObjectCache object. Unfortunately, not all these technologies share the same programming interface, which is annoying especially if you compare ObjectCache and the ASP.NET Cache. However, there’s enough room for you to write some adapter code to make them interchangeable under the hood of the abstract interface.

Another benefit that a cache wrapper provides is testability. ASP.NET Web Forms is not designed with testability in mind so having some sort of ICacheService interface is the only way to test code that deals with cached data. Curiously, taking such a route is also the best approach in ASP.NET MVC.

Mocking the Caching Layer in ASP.NET MVC

Suppose you have code in your ASP.NET MVC controllers (or other layers) that uses the ASP.NET Cache object. How would you test this code in isolation? ASP.NET MVC lets you mock up the intrinsic objects that populate the HTTP context of a request. For example, Figure 2 shows a test written for a controller method that uses Session internally. The test uses RhinoMocks.

You first mock up the HttpContextBase class—the parent class of HttpContext—and then make the mock object return an instance of your test-specific FakeSession class whenever the Session property is read. Finally, you bind the mocked HttpContext to the controller instance. From now on, any action the controller performs on HttpContext.Session passes through the FakeSession class.

You can consider this a standard approach to mock up any ASP.NET intrinsic objects. Is the Cache object an intrinsic object of the ASP.NET runtime? Not in the implementation of HttpContextBase. The HttpContextBase class has a Cache property, but you can’t mock it up because the property doesn’t represent an abstraction of the ASP.NET cache; instead, it's a concrete implementation. Here’s how the Cache property is declared on the HttpContextBase class:

public abstract class HttpContextBase : IServiceProvider


    public virtual Cache Cache { get; }     public virtual HttpSessionStateBase Session { get; }



The type of the Cache property is actually System.Web.Caching.Cache—the real cache object, not an abstraction as it is for Session and other objects. Also, the Cache type is sealed; it's not mockable and it's unusable in isolated unit tests. What can you do? You have two options: you can use a tool designed to mock sealed classes or you can use a wrapper around any access to the cache. Sample tools that let you mock the un-mockable are TypeMock isolator (a commercial product) and Moles, which is from Microsoft Research.

By wrapping any access to the ASP.NET cache in a service provider class, such as any class that implements the ICacheService interface, all you need to do is inject a valid test double class in any unit test. Modifying your controller code to replace Cache with ICacheService is a plain refactoring task, and not that complex. Figure 3 shows a possible way to rewrite your ASP.NET MVC controllers. Testing this is now quite simple, as Figure 4 shows. Figure 5 shows what the FakeCache class can look like.

Moles, the tool from Microsoft, is a framework that lets you test what normally might be hard or impossible to test, such as static methods, extension methods, non-virtual methods, and sealed classes. An extension to Visual Studio 2010, Moles works by creating strongly typed wrapper classes that redirect any .NET method to a user-defined delegate. You don’t have to create such delegates yourself; they're automatically created for you by the code generator embedded in the framework. You can read more about Moles at

ObjectCache in ASP.NET 4

Some new possibilities for caching within ASP.NET applications are offered by the ObjectCache class introduced with the .NET Framework 4.0. Added to a new assembly (System.Runtime.Caching), and decoupled from System.Web, the class works just like the Cache object. The class was introduced to make caching capabilities available to applications other than ASP.NET applications. The framework comes with a base class ObjectCache and a single implementation—the MemoryCache object.

Creating a custom cache is easy, too. All you need to do is derive your own class from ObjectCache and override a few methods, such as Get and Set. In the end, it's not much different from creating your own cache service, as discussed earlier.

By using the ObjectCache class you're no longer limited to having a single cache object; you can have multiple objects that store different copies of the same data or different segments. Note, though, that ObjectCache is not a distributed cache and you have no built-in infrastructure to load-balance content and offer a unified API. In other words, if you support multiple cache objects, it's your responsibility to keep them in sync—and read/writes must be specific to each object.

The programming interface of ObjectCache is analogous to Cache but not identical. Two differences are worth noting. First, you can’t store a null value into the cache. Second, the ObjectCache container is enumerable and as such it supports the LINQ query API. The programming interface of the base ObjectCache class provides parameters to identify regions. However, the MemoryCache concrete implementation doesn’t support regions. Supporting regions is up to the actual caching provider.

Don't Limit Yourself

Microsoft recommends that you stop using the Cache object in ASP.NET 4 and that you step up to ObjectCache. I agree that the Cache object becomes more inadequate every day. It still works well for simple scenarios; it's out of place for enterprise-class applications with strong cache needs.

Having said that, I recommend that you first refactor your code to support a caching provider. First, create your own cache wrapper. This gives you the benefit of supporting only the functionality you need. However, when you need CRUD, rich expiration policies, change monitors, and query capabilities, instead of creating your own cache provider model from scratch, you would use ObjectCache as the caching abstraction. In doing so, you can avoid having a cache provider based on the ASP.NET Cache and replace it with one that uses MemoryCache. In addition, you can create custom caches based on AppFabric Caching Services or other products. Caching in web applications is important—don’t limit yourself to the classic ASP.NET Cache object.

Dino Esposito is a trainer and consultant specializing in web architectures and effective code design principles and practices. He's also the author of Programming ASP.NET MVC 2 (Microsoft Press) and co-author of Microsoft .NET: Architecting Applications for the Enterprise (Microsoft Press). Get in touch via
Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.