Caching: What, How and When

Know how to use - and when to use - this ASP.NET feature.

ask asp.netNOW





Caching: What, How and When

Know how to use - and when to use - this ASP.NET feature.


By Josef Finsel


I've heard a lot about caching in ASP.NET. Should I cache all my pages?

 - S.M., Denver, Colo.


The short answer is "no." But to understand that answer, let's take a look at how caching has evolved in ASP.NET.


Built into the Web server is a type of internal caching that takes frequently requested objects and stores them in memory. Let's say you have a logo that appears on all your pages. The first time a page is requested, the Web server reads the logo from disk and send it across the wire. But it also stores that image in memory. The next time a page requiring that logo is read, the server will supply the logo from memory (though it will still register the request to the log). Thus, the server determines how long it should keep objects in memory and when they should be flushed. This is an output cache.


Before .NET, developers had limited ability to control page caching using the Server.Response object:


Response.Expires = 100;


This would cache the page for 100 seconds on the server. Setting the value to 0, or a negative number, would tell the server not to cache the page at all. This was good for caching many pages at a time, but wasn't a good idea for smaller amounts of data. Not only that, but you couldn't get at cached data - it simply existed, out of reach. This all changed with ASP.NET.


With ASP.NET, the cache is much more accessible, and putting things into the cache and modifying things in the cache is much easier. The easiest way to cache a page is to use the OutputCache directive at the top of your page:


<%@ OutputCache Duration="60"

 VaryByParam="None" Location="Server" %>


Let's take a quick look at this directive. The first parameter is the Duration, in seconds. This is how long the page should remain in cache. Every time the page is requested, the cache countdown begins; in this instance, it lasts 60 seconds. The second parameter is VaryByParam, which specifies how smart the caching is.


As an example, take a site that has content accessed by a query string: http://localsite/customerinfo.aspx?CustID=2. This is the same page as http://localsite/customerinfo.aspx?CustID=3, but with different information. If you are caching information and have VaryByParam set to none, both pages display the same information until the cache expires.


The neat thing about VaryByParam is it allows you to define the parameters that determine whether the page is cached. Take a look at this example:


<%@ OutputCache Duration="60"

 VaryByParam="CustID" Location="Server" %>


In this case, if CustID is the same, the server will use the cached version; otherwise, it will deliver a new version. Figure 1 shows a few more URLs and how the server will respond



Server response


New Page 1


New Page 2


Serve Cached Page 1

Figure 1. The server responds differently to URL requests, depending on how the VaryByParam parameters are set.


The final item I want to discuss in the OutputCache directive is the Location. If you don't specify the Location, the page will attempt to cache itself wherever most convenient - most likely on the client. You can specify Client, Server, or None (None disables output caching), or you can specify Downstream, which places the cached page on any HTTP1.1 cache-capable device. This could include the client or a proxy server, which can be a handy way of network engineering if you have an intranet that uses a proxy server and you can store the cache there rather than on your server.


The problem with using the OutputCache directive is it is a very broad blade and sometimes you need something finer. For example, say you have a page that contains a combination of static and dynamic content (or even dynamic content that appears static to the person browsing the Web page). A good example of this would be the navigation menus on a site that stay the same for each page while the content in the page changes. ASP.NET finally gives you a fine enough blade to cut out portions of a page for caching. This is done by caching the controls without caching the entire Web page.


If you take a look at, you'll quickly notice that the menus on the left and the header across the top are the same on every page. This because these are Web controls - separate files that ASP.NET loads on every page. To prevent the server from having to load these controls with every page, the controls include an OutputCache directive. The page hosting the control, however, does not; this caches the control.


The most exciting new part of caching in ASP.NET, however, is data caching. Data caching allows you to store commonly used data so it doesn't have to be reloaded every time it's needed. In order to keep the example simple, I'm not using a database or any other external source, but I'm simply getting a string of pangrams either from cache or creating them and storing them in cache if they weren't there:


// Attempt to get the data from the cache

string strData = (string)Cache\\["Output"\\];

// If the string isn't null, the data was in the cache

if (strData != null) // Data was stored in cache

\\{ ... \\}


//Data wasn't in the cache so we must create and cache it


   // Set the cache expiration for 30 seconds

   DateTime tmExpire =


    // Cache the data with no dependencies,

   // a 30-second absolute expiration,

   // and no sliding expiration.

   Cache.Insert("Output", strData, null, tmExpire,

    System.TimeSpan.FromMinutes(0) );



I've cut out the extra code (you can download the complete sample), but the previous example has the important parts. To begin with, I attempt to get the data out of the cache. If there is no data, the object will be null (Nothing in VB.NET). Data in the cache is referenced by a string name (in this case, Output).


You can cache data in several ways, but I'm using the full Insert method to set the expiration time rather than using defaults. To do this, I take a DateTime object set for 30 seconds from now and use it for the absolute expiration. For the SlidingExpiration (the last parameter in the insert method), I use 0 minutes. SlidingExpiration resets the expiration based on the time the object was last accessed.


If you load this page and connect to it, you'll get a message saying the data was created because it wasn't in cache, a label telling you when the cache will expire, a label telling you what the current server time is, and, finally, the data.


Hit refresh and you'll witness something interesting. It appears the data was re-created rather than retrieved from the cache! What's going on? The trick is also to look at the current server time, which stays the same. This is because the top of this page contains an OutputCache directive of five seconds. You can refresh all you want, but the page won't change until at least five seconds have passed. Then you'll see the data was retrieved from the cache and the server time is updated, at least until the next five-second block goes by. If you continue to refresh, you'll notice - after 30 seconds have passed - that the cache expires and the page is rebuilt.


One last point about data caching: It's global. If you open a new browser on a totally separate machine and point it to this Web page, it will show the cached data. Data caching takes place on the server, so you don't really want to store individual data in cache there. Using data islands is a better solution.


Therefore, the summary answer to the question, "Should you cache all your pages?" is to evaluate what you're doing and see what you can cache. WebControls are likely items to cache, though you might have to specify whether the control is parameter-driven and if it requires multiple copies cached. Data that is used site-wide and is fairly static is a good candidate for data caching. And, don't hesitate to experiment.


The file referenced in this article is available for download.


Have a question? Send it to [email protected].


Josef Finsel is a software consultant with G.A. Sullivan, a global software development company. He has published a number of VB and SQL Server-related articles, and he is working on the syntax for FizzBin.NET, a programming language that works the way programmers have always suspected. He also wrote The Handbook for Reluctant Database Administrators (Apress).




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.