ASP.NET Page Output Caching

An Effective Page Output Caching Layer Can Benefit Your Application

Dino Esposito

October 30, 2009

11 Min Read
ITPro Today logo in a gray background | ITPro Today

CoreCoder

LANGUAGES: C#

ASP.NETVERSIONS: 1.x | 2.0

 

ASP.NET Page Output Caching

An Effective Page Output Caching Layer Can Benefit Your Application

 

By Dino Esposito

 

Do you remember the bug in the Pentium s floating pointprocessor that was in the news for a while some years ago? Simply put, that bugcould cause applications to return incorrect results for certain mathoperations with certain numbers. The bug was caused by a bad value mistakenlyinserted in one of the reference tables used by the floating point processor tospeed up its own calculation work. A reference table is a matrix ofprecalculated, cached values that floating point units use to acceleratecalculation. Well, how does this relate to ASP.NET and page output caching?Caching data any sort of data is always a way to improve performance in anysort of application.

 

What is page output caching, ultimately? It s adynamically changing reference table that contains HTML markup instead offloating point numbers. The ASP.NET HTTP runtime, like the CPU s floating pointunit, looks up the table for a valid entry. If a matching entry is found, it isloaded and used instead of processing the request. If no valid entry is found,then the request is processed as usual. The resulting page output will becached in the internal table, and will stay there, ready to serve the nextincoming requests for the same page.

 

As you can imagine, page output caching can provideseveral benefits to your applications. However, to make sure that there are nosnags or loose ends, you should carefully consider a few caveats.

 

Look Before You Cache

The key advantage that page caching brings to the table ispretty obvious your application s throughput, defined as the number of servedrequests per second, is substantially increased. A cached page is not supposedto stay in the cache indefinitely. Giving pages a thoughtful durationcontributes to keeping the overall execution time low. Even aduration of one second can mark the difference; but sometimes a too-longduration, combined with a relatively infrequent use of the page, can raise moreissues than it attempts to resolve. Page output caching is a way to stave offprocessing time as a result of bypassing the ASP.NET HTTP runtime. The more acached page is requested, the more you gain in terms of shorter response time.The less a cached page is requested, the more you pay in terms of memoryoccupation. The phenomenon gets even sharper if the page has been assigned along cache duration. A short duration, in fact, would invalidate the pagesooner, thus freeing some valuable memory.

 

Which kind of pages take mostadvantage of caching features? Good candidates for output caching arerelatively static, readonly pages such as those describing a product or showingperiodical reports. In general, the ideal candidate for the cache is any pagethat is frequently accessed and displays global information that all usersshare. You are also encouraged to cache pages that show live data, as long asit is acceptable to your users to have data delayed by some interval. Forexample, it is fine to cache a page showing a chart that is updated every hour.In this case, you can set the cache duration to 60 minutes and have bothupdated data and maximum performance.

 

As mentioned, a product page seems to be the perfectcandidate for caching. However, a product page is normally a unique page thatselectively displays product information based on a query string parameter:

 

http://www.YourServer.com/product.aspx?id=899191

 

How would it work in this case? The ASP.NET page-cachingmechanism allows you to specify a handful of parameters to vary pages and cachemultiple copies of the same page. You can choose a query string attribute (forexample, the id attribute in the sample URL above) and have ASP.NET save a copyof the page for each distinct value invoked for the attribute. Let s drill downthe capabilities of the @OutputCache directive the syntax element thatenables and configures page output caching.

 

Explore the @OutputCache Directive

To be precise, output caching can either be configureddeclaratively through the @OutputCache directive or programmatically throughthe interface of the HttpCachePolicy class. The directive works with bothASP.NET pages and user controls, and lets you declaratively set the cachingcapabilities of the page or control. The directive accepts a variety ofattributes, a couple of which (Duration and VaryByParam) are mandatory.

 

The Duration attribute indicates for how long the systemshould keep the page output cached. The Duration is expressed in seconds. TheVaryByParam attribute allows you to vary the cached output depending on thecontents of the query string or the field values posted through a POSTstatement. For example, the following declaration will cache the page for oneminute, regardless of any query string or form parameters:

 

<%@ OutputCache Duration="60"VaryByParam="None" %>

 

The @OutputCache directive is made up of six attributesthat indicate the location of the cache, its duration, and the arguments to useto vary page caching (see Figure 1). As mentioned, VaryByParam is a requiredattribute whose absence makes the page throw an exception. The empty string isnot an acceptable value; if you don t want to vary the page output by anyparameters, simply set it to None.

 

Attribute

Description

Duration

The time, in seconds, that the page or user control is cached.

Location

Specifies where to store the output of a page. The attribute takes its value from the OutputCacheLocation enumeration. The default is Any.

VaryByCustom

A semicolon-separated list of strings that lets you maintain distinct cached copies of the page based on the browser type or user-defined strings.

VaryByHeader

A semicolon-separated list of HTTP headers.

VaryByParam

A semicolon-separated list of strings representing query string values sent with GET method attributes, or parameters sent using the POST method.

VaryByControl

A semicolon-separated list of strings representing fully qualified names of properties on a user control. Only valid for caching user controls; don t use it with ASP.NET pages.

Figure 1: The sixattributes of the @OutputCache directive.

 

In addition to GET and POST parameters, a page can bevaried by HTTP headers and by custom techniques. Imagine you have a page with thefollowing directive:

 

<%@ OutputCache Duration="60"VaryByParam="None"

 VaryByHeader="DinoE" %>

 

What s the result? The page is cached and stored for oneminute if the request contains a header named DinoE. The first time a similarrequest comes in, the page is processed by the pipeline and its output is cachedto memory. Next requests for the same page that don t include the header areserved as usual; for others, the markup is retrieved from the cache and servedto the user.

 

The VaryByCustom attribute allows you to vary the versionsof page output by a sort of logical hash calculated on the page. TheVaryByCustom attribute is set to a user-defined string; this string is thenpassed to an overridable method on the HttpApplication class GetVaryByCustomString.

 

GetVaryByCustomString uses the input string as an argumentto calculate the vary-by string, which is then returned to the pipeline. Insummary, the string to vary the page output is programmatically determined andidentified by a public name that is the string you assign to VaryByCustom.

 

The default implementation of VaryByCustom supports onespecial string (browser), which indicates that pages will be varied on thebrowser type:

 

<%@ OutputCache Duration="60"VaryByParam="None"

 VaryByCustom="browser"%>

 

The real string used to vary the page output is composedby the browser name and major version number. In particular, the string is whatreturns the Type property of the HttpBrowserCapabilities object. To overridethis behavior, or to add more custom strings, add the code shown in Figure 2 tothe global.asax file.

 

public override string GetVaryByCustomString(

    HttpContext context,string custom)

{

   // Handles the Browserstring

   if (custom =="browser")

       returncontext.Request.Browser.Type;

   // Handles your ownstrings

   if (custom =="...")

       return ...;

   return null;

}

Figure 2:Overriding GetVaryByCustomString in the global.asax file.

 

Caching Locations

Under IIS 5.0, the output caching mechanism requires that anew HTTP application be created, although only for a short time. A system HTTPmodule hooks up the ASP.NET request and verifies that a cached copy for thepage exists. If a copy is found, it is retrieved from the cache and served.Output caching is certainly effective in this way, but it would be even morebeneficial to applications if implemented within IIS. This is exactly whathappens with IIS 6.0. With Microsoft Windows Server 2003 and the IIS 6.0process model, the output caching is integrated in the Web server, resulting inmuch better performance and responsiveness. In other words, IIS 6.0 providesoutput caching capabilities that an ASP.NET page can control through thestandard API. Pages are no longer cached within the ASP.NET worker process, butinstead are stored within the IIS boundaries. As a result, no extra HTTPapplication must be created to serve a request from the cache.

 

The output cache can be located in various places, eitheron the client that originated the request or the server. It can also be locatedon an intermediate proxy server. By default, a cacheable page is cachedanywhere client, server, and proxy, if any exists. You set the Locationattribute of the @OutputCache directive to decide about the location. If thechosen value is Client, then the Expires header is added set to the properduration. If the location is Server, then the page output is stored in theCache object. Another feasible value is DownStream. In this case, the page canbe cached both on the client and in the memory of any intermediate proxy. TheExpires header is set according to the value of the Duration attribute, and nocopy of the page output is maintained by ASP.NET.

 

Portions of the Page

The capability of caching the output of Web pages ishelpful, but sometimes caching the entire content of a page is not possible, oris simply impractical. Some pages, in fact, are made of pieces with radicallydifferent features as far as cacheability is concerned. In these situations,being able to cache portions of a page would be an incredible added value.ASP.NET user controls are the solution to the problem because they supportoutput caching features in much the same way a page does. If you want to beable to cache the output of a portion (or various portions) of a page, you simplymove that portion of the page to a user control and configure the @OutputCachedirective of the user control accordingly. The VaryByControl attribute of thedirective (which is specifically designed for cacheable user controls) lets youcache copies of the user control per each distinct value of some controlproperties.

 

What s New in ASP.NET 2.0

In the Beta 1 version of ASP.NET 2.0, @OutputCachesupports two additional attributes, Shared and SqlDependency. The Sharedattribute indicates whether the output of a user control is shared amongmultiple pages using that control. The default is false, meaning that each pagewill have its own copy of the control s output. As you can see, the Sharedattribute works only for user controls. The SqlDependency attribute indicates adependency on the specified table on a given SQL Server database. Whenever thecontents of the table change, the page output is removed from the cache.

 

The SqlDependency attribute binds the output of thecontaining page to the state of a particular table in a SQL Server 7.0 or SQLServer 2000 database. Here s an example:

 

<% @OutputCache Duration="3600"VaryByParam="none"

 SqlDependency="Northwind:Employees"%>

 

A page or a user control that contains this code snippethas its output cached for an hour or until a record changes in the Employeestable in the Northwind database. Note that the Northwind string here is not thename of a database, but the name of an entry in the new sectionof the configuration file. That entry contains detailed information about theconnection string to use to reach the database. For the mechanism to work, thedatabase and the table must be enabled for change notification.

 

Multiple dependencies can be specified by separatingmultiple database:table pairs with a semicolon in thevalue of the SqlDependency attribute. If you re setting the attribute whileusing SQL Server 2005, you must give the attribute the name of a commandnotification object as its value. The command notification object embedsinformation about the connection string, the database, and the particular queryrun. In this case, the page output caching mechanism will benefit from the SQLServer s capabilities of monitoring for changes in the results of a query andnot a full table.

 

To finish off with the changes in the upcoming version ofASP.NET, a word about the substitution mechanism is in order. In ASP.NET 1.x,you can cache the whole page or a part of it. There s isn t anything thatallows you to cache all the page but a portion. Thisis just what you get in ASP.NET 2.0 through the tag. Any markup wrapped by the tag is considered dynamic and never cached,regardless of the settings of the @OutputCache directive.

 

Dino Esposito is aWintellect trainer and consultant who specializes inASP.NET and ADO.NET. Author of ProgrammingMicrosoft ASP.NET and IntroducingASP.NET 2.0, both from Microsoft Press, Dino also helped severalcompanies architect and build effective products for ASP.NET developers. Dinois the cofounder of http://www.DotNet2TheMax.com,a popular portal for .NET programmers. Write to him at mailto:[email protected] or jointhe blog at http://weblogs.asp.net/despos.

 

 

 

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like