Fragment Caching

In Chapter 5, I briefly touched on the subject of output caching and described how to improve the performance of Web forms by including @ OutputCache directives in your ASPX files. For example, adding the statement

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

to an ASPX file instructs ASP.NET to generate the page once and to hold a copy of it in the output cache for 60 seconds. Until one minute elapses and the cached page becomes invalid, ASP.NET satisfies subsequent requests for the page by returning cached HTML. Caching improves performance by preventing a page from having to be executed over and over again to obtain its output.

One of the limitations of using @ OutputCache directives in ASPX files is lack of granularity. You either cache the entire page or nothing at all: there鈥檚 no in-between. User controls offer a middle ground by allowing portions of a page to be cached while the rest continues to be generated dynamically. Called sub-page caching or fragment caching, this form of caching is a boon to performance because it enables ASP.NET output caching to be used with pages that mix static and dynamic content.

Here鈥檚 how fragment caching works. You begin by apportioning your pages into areas that contain static content (content that doesn鈥檛 change from request to request and is therefore amenable to caching) and areas that contain dynamic content (content that changes鈥攐r could change鈥攆rom request to request and should therefore not be cached). Then you implement the static portions of the page as user controls. In the controls鈥?ASCX files, you include @ OutputCache directives that enable output caching. Significantly, caching is performed just for the content generated from the ASCX files and not for other content on the page. You can even include VaryByControl attributes in @ OutputCache directives to cache different instances of the same control based on the property values assigned to those instances.

Perhaps an example or two will help clarify matters. You might have noticed that the MyQuotes application presented earlier in this chapter is slow. Every time you check the Show Quotes box, the control retrieves stock prices from a Web service. You could alleviate the performance problem somewhat by adding an @ OutputCache directive to MyQuotes.aspx, but if the page contained other controls (and in real life it would), their output would be cached, too. A better solution is to add the following directive to MyQuotes.ascx:

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

Now only the stock quotes grid will be cached and you鈥檙e free to generate content dynamically elsewhere on the page. Sure, stock quotes can now be up to 60 seconds out-of-date, but when they鈥檙e delayed for 20 minutes anyway, who cares? You just freed up your Web server to process potentially thousands more requests per second.

Admittedly, this example is overly simplistic because MyQuotes is such a simple control: it looks the same on every Web page. This chapter鈥檚 XmlNavBar control offers a more realistic example. Once initialized, an XmlNavBar never varies its HTML output unless its properties are changed dynamically. That means it lends itself extraordinarily well to output caching. However, you might use several XmlNavBars on your site and configure each of them differently, in which case different versions of the control need to be cached.

That鈥檚 what the VaryByControl attribute is for. With it, you can instruct ASP.NET to cache different versions of a user control based on the property values assigned to it. For example, if you use two different XmlNavBar controls and initialize each with a different XML file, you could cache a version for each XML file by listing the XmlSrc property in a VaryByControl attribute:

<%@ OutputCache Duration="3600" VaryByParam="None"  VaryByControl="XmlSrc" %>

If you customize XmlNavBar controls by varying multiple properties, you can separate the property names with semicolons in the @ OutputCache directive:

<%@ OutputCache Duration="3600" VaryByParam="None"
  VaryByControl="XmlSrc;ForeColor;MouseOverColor" %>

Now the control won鈥檛 be physically executed more than once an hour, and no matter how many pages contain XmlNavBars and how often those pages are requested, you鈥檝e reduced the load on your server commensurately. That鈥檚 a bargain by any measure.

Incidentally, ASP.NET performs output caching on a per-application basis. That means if you use two different navbars in two different applications, you don鈥檛 have to bother with VaryByControl attributes. ASP.NET will automatically cache two versions.