Output Caching in ASP.NET 2.0By Scott Mitchell
One of the most sure-fire ways to improve a web application's performance is to employ caching. Caching takes some expensive operation and stores its results in a quickly accessible location. ASP.NET version 1.0 introduced two flavors of caching:
- Output Caching - caches the entire rendered markup of an ASP.NET web page or User Control for a specified duration.
- Data Caching - a programmatically-accessible, in-memory data cache for storing objects in the web server's memory.
In ASP.NET 2.0, the caching system has been extended to include SQL cache dependencies, cache profiles, and post-cache substitution for output cached pages. The Caching for Performance section of the ASP.NET 2.0 QuickStarts provides a good overview of ASP.NET 2.0's caching options. This article explores output caching in ASP.NET 2.0, starting with an overview of output caching and followed by a detailed look at creating pages that include both cached and non-cached markup using fragment caching and post-cache substitution techniques. Read on to learn more!
An Overview of Output Caching
Output caching improves the performance of an ASP.NET application by caching the rendered markup of an ASP.NET web page and serving this content instead of re-rendering the page. For example, imagine that you had an ASP.NET page that displayed the records from a database table named
Employeesthat listed the current employee information. Without caching, each time this page is accessed a connection is made to the database, the table queried, and the results returned to the requesting client. But how often does the employee information change? Probably not more than once a day or so, making many of those requests to the database superfluous. With output caching, when this page is first visited the rendered HTML will be cached for a specified duration. During that time period, if a user requests this page, the cached markup will be returned, thereby saving the database access and page rendering costs.
That's output caching in a nutshell! To implement output caching, simply add the
<% @OutputCache %> directive
to the top of your page like so:
duration is the number of seconds for which the rendered markup remains in the cache. paramList is a list of parameters
whose values vary the cache. For example, if the page that displays employees displays just those employees in a particular
department as determined by a querystring parameter, then we want to vary the cache by this parameter. To be more precise,
imagine that our employee page displays a particular department's employees when visited like
If the cache is not varied by any parameter then when a user visits
ShowEmployees.aspx?DepartmentID=Sales, the employees
in the sales department will be returned and that markup will be cached. If within that cache duration a user visits
ShowEmployees.aspx?DepartmentID=IT, they will still see the cached sales staff rather than the IT staff.
To fix this, we simply need to instruct the output cache engine to vary its cache by the
To vary by all parameters, use an asterisk (
*); to vary by no parameters, use "None".
|Output Caching Subtleties|
While output caching is painfully easy to implement - just add the |
Looking Into the Guts of Output Caching
Output caching is implemented in ASP.NET as an HTTP Module, in particular the
OutputCacheModuleclass in the
System.Web.Cachingnamespace. An HTTP Module listens to the events that fire during the lifecycle of a request and can execute code when a particular events fire. The
OutputCacheModuleHTTP Module subscribes to the
UpdateRequestCacheevents. In the
ResolveRequestCacheevent, the module determines if the file being requested participates in output caching and, if so, there's a cache version to send back. If there's not a cached version, the page is rendered as normal. On the way out when the
UpdateRequestCacheevent fires, the module will cache the rendered output (if the page is setup to support output caching). The following sequence diagram oversimplifies the tasks performed by the
OutputCacheModulemodule, but highlights the overall workflow.
If you want a page's output cache to expire before the specified duration is reached, there are two options.
You can programmatically remove the output cached content for a particular page by calling the
method, where path is the virtual absolute path to the page. You can also associate external dependencies with
the output cache, as discussed in Caching Page Output with Cache Key Dependencies.
This includes the ability to tie a SQL Cache Dependencies to the output cache for a page; see the
SQL Cache Invalidation section
of the ASP.NET 2.0 QuickStarts for more information.
Output Caching Only Part of a Page
By default, output caching caches the entire rendered markup of a page. Oftentimes, we want to keep certain portions of the page dynamic, though. We may want to cache the expensive, non-changing items - displays of data, for instance - but keep advertisements, user-specific data, or other oft-changing information "live". In ASP.NET 1.x this could only be done via fragment caching, which allows you to say, "Keep this page dynamic except for these portions." ASP.NET 2.0 supports fragment caching, but also introduces a post-cache substitution model which allows you to say the opposite: "Keep this page cached except for these dynamic portions." Let's look at fragment caching first and then turn our attention to post-cache substitutions.
Fragment caching works by creating a page without output caching that uses a User Control that does use output caching.
The download at the end of this article includes a simple example - there's a User Control named
that displays the records from a database table along with the date/time at which the data was retrieved. This User Control contains
<% @OutputCache %> directive:
The page that contains this User Control does not have an
<% @OutputCache %> directive. The net
result is that the page is re-rendered every time it's visited, but the User Control is only re-renderd (and therefore only
hits the database) at most once every 15 seconds.
The following screenshot shows the page when it is first visited. Note that the date/time for the page and the User Control are the same. Revisiting the page a few seconds later, however, shows that the User Control is being cached - the page's date/time is up to the second, but the User Control time is from when it was first visited.
Check out the download available at the end of this article for the page and User Control used in this sample. Also, see How To Perform Fragment Caching in ASP.NET by Using Visual C# .NET for a step-by-step look at a fragment caching demo.
Making Cached Portions of a Page Dynamic Through Post-Cache Substitutions
ASP.NET 2.0 adds another technique to mix cached and dynamic content - post-cache substitutions. As the name implies, this approach takes a page that uses output caching and allows you to make "live" substitutions in the cached content. There are two ways that post-cache substitutions can be applied:
- Declaratively - specify the dynamic portion(s) of a page using Substitution controls. You need to create a method that will be invoked by these controls in order to get their rendered markup.
- Programmatically - the
Response.WriteSubstitution(callback)method programmatically injects a response substitution block. The callback parameter is a delegate to a method that will be invoked to get the markup to emit.
specifies a static method in the page's code-behind class that must accept an
HttpContext object and return the
string to emit. Imagine that we had a page that included cached data, but we wanted to include a dynamic message (an advertisement, perhaps). We could add a
Substitution control to the page where we wanted the message to appear:
Here we specified the
GetMessage. Therefore, we need to create a static method in
the page's code-behind class named
GetMessage that returns a string:
When this page is visited, its content will be cached, as usual. On subsequent visits, though, when the page is
still cached, the
OutputCacheModule will invoke the
GetMessage method and place its output in
the appropriate sections of the page.
ASP.NET's output caching feature allows for a page or User Control's entire HTML output to be cached, thereby helping to boost the application's overall performance. The output caching logic is handled by an HTTP handler,
OutputCacheModule. Oftentimes, a page needs to have some portions be cached, while leaving others dynamic. ASP.NET 2.0 provides two mechanisms to accomplish this - fragment caching and post-cache substitutions. With fragment caching, the page is left as a normal, dynamic page without output caching. Those regions of the page that should be cached, however, need to be implemented as User Controls that are configured to use output caching. The other avenue is to use post-cache substitution, where the page is configured to use output caching. Substitution controls can be added to the page to indicate areas where content should be dynamically generated on each page visit regardless of whether the page is cached. Post-cache substitutions are new to ASP.NET 2.0.