You enable Page Output Caching by adding an <%@ OutputCache %> directive to a page. For example, the page in Listing 23.1 caches its contents for 15 seconds. Listing 23.1. CachePageOutput.aspx
The page in Listing 23.1 displays the current server time in a Label control. The page also includes an <%@ OutputCache %> directive. If you refresh the page multiple times, you will notice that the time is not updated until at least 15 seconds have passed. When you cache a page, the contents of the page are not regenerated each time you request the page. The .NET class that corresponds to the page is not executed with each page request. The rendered contents of the page are cached for every user that requests the page. The page is cached in multiple locations. By default, the page is cached on the browser, any proxy servers, and on the web server. In Listing 23.1, the page is cached for 15 seconds. You can assign a much larger number to the duration attribute. For example, if you assign the value 86400 to the duration parameter, then the page is cached for a day. Note There is no guarantee that a page will be cached for the amount of time that you specify. When server memory resources become low, items are automatically evicted from the cache. Varying the Output Cache by ParameterImagine that you need to create a separate master and details page. The master page displays a list of movies. When you click a movie title, the details page displays detailed information on the movie selected. When you create a master/details page, you typically pass a query string parameter between the master and details page to indicate the particular movie to display in the details page. If you cache the output of the details page, however, then everyone will see the first movie selected. You can get around this problem by using the VaryByParam attribute. The VaryByParam attribute causes a new instance of a page to be cached when a different parameter is passed to the page. (The parameter can be either a query string parameter or a form parameter.) For example, the page in Listing 23.2 contains a master page that displays a list of movie titles as links. Listing 23.2. Master.aspx
If you hover your mouse over the links displayed in Listing 23.2, you can see the query string parameter passed by each link in the browser status bar (see Figure 23.1). For example, the first movie link includes a query string parameter with the value 1, the second link includes a query string parameter with the value 2, and so on. When you click a movie link, this query string parameter is passed to the details page in Listing 23.3. Figure 23.1. Displaying the Master page.Listing 23.3. Details.aspx
The page in Listing 23.3 uses a DetailsView to display detailed information on the movie selected from the master page (see Figure 23.2). The DetailsView is bound to a SqlDataSource control that includes a QueryStringParameter SELECT parameter that represents the id query string parameter. Figure 23.2. Displaying the Details page.Notice that the Details.aspx page includes an <%@ OutputCache %> directive. The VaryByParam attribute in the <%@ OutputCache %> directive has the value id. If you request the Details.aspx page with a different value for the id query string parameter, then a different cached version of the page is created. It is important to understand that using VaryByParam results in more caching and not less caching. Each time a different id parameter is passed to the Details.aspx page, another version of the same page is cached in memory. The Details.aspx page displays the current time. Notice that the time does not change when you request the Details.aspx page with the same query string parameter. You can assign two special values to the VaryByParam attribute:
You also can assign a semicolon-delimited list of parameters to the VaryByParam attribute when you want to create different cached versions of a page, depending on the values of more than one parameter. Varying the Output Cache by ControlThe VaryByControl attribute enables you to generate different cached versions of a page depending on the value of a particular control in the page. This attribute is useful when you need to create a single-page Master/Details form. For example, the page in Listing 23.4 contains both a DropDownList and GridView control. When you select a new movie category from the DropDownList, a list of matching movies is displayed in the GridView (see Figure 23.3). Figure 23.3. Displaying a single-page Master/Details form.Listing 23.4. MasterDetails.aspx
The page in Listing 23.4 contains an <%@ OutputCache %> directive. This directive includes a VaryByControl parameter. The ID of the DropDownList control is assigned to this parameter. If you neglected to add the VaryByControl attribute, then the same list of movies would be displayed in the GridView regardless of which movie category is selected. The VaryByControl attribute causes different cached versions of the page to be created whenever the DropDownList represents a different value. Varying the Output Cache by HeaderAnother option is to use the VaryByHeader attribute to create different cached versions of a page when the value of a particular browser header changes. Several standard browser headers are transmitted with each page request, including
For example, the page in Listing 23.5 includes an <%@ OutputCache %> directive that has a VaryByHeader attribute with the value User-Agent. When you request the page with different browsers, different versions of the page are cached. Listing 23.5. VaryByHeader.aspx
I don't recommend using the VaryByHeader attribute with the User-Agent header. The problem with this attribute is that it is too fine-grained. If there is any variation in the User-Agent header, then a different cached version of a page is generated. Consider the User-Agent header sent by the Internet Explorer browser installed on my computer. It looks like this: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) This header includes the major and minor version of the browser, the platform (Windows XP), a string indicating that Service Pack 2 has been installed (SV1), and the versions of the .NET framework installed on my machine. If someone else requests the same page with a slight difference in the User-Agent header, then a different cached version of the page is generated. In other words, the web server must do more work rather than less, which defeats the point of caching. Instead of using the VaryByHeader attribute, I recommend that you use the VaryByCustom attribute described in the next two sections. Varying the Output Cache by BrowserA better way to create different cached versions of a page that depend on the type of browser being used to request the page is to use the VaryByCustom attribute. This attribute accepts the special value browser. When VaryByCustom has the value browser, only two attributes of the browser are considered important: the type of browser and its major version. For example, a page request from Internet Explorer results in a different cached version of the page than does one from FireFox. A page request from Internet Explorer 5 rather than Internet Explorer 6.5 also results in a different cached version. Any other variations in the User-Agent header are ignored. The page in Listing 23.6 illustrates how you can use the VaryByCustom attribute with the value browser. The page displays the current time and the value of the User-Agent header. If you request the page with Internet Explorer and request the page with Firefox, different cached versions of the page are created. Listing 23.6. VaryByBrowser.aspx
Varying the Output Cache by a Custom FunctionThe VaryByCustom attribute is named the VaryByCustom attribute for a reason. You can specify a custom function that determines when a different cached version of a page is generated. You can use any criteria that you please with the custom function. You can create different cached versions of a page depending on the browser minor version, the browser DOM support, the time of day, or even the weather. You create the custom function in the Global.asax file by overriding the GetVaryByCustomString() method. For example, the Global.asax file in Listing 23.7 illustrates how you can override the GetVaryByCustomString() method to create different cached versions of a page depending on a particular feature of a browser. If the VaryByCustom attribute in a page has the value css, then the function returns a string representing whether or not the current browser supports Cascading Style Sheets. Listing 23.7. Global.asax
The page in Listing 23.8 displays one of two Panel controls. The first Panel contains text formatted with a Cascading Style Sheet style and the second Panel contains text formatted with (outdated) HTML. Depending on whether a browser supports CSS, either the first or second Panel is displayed. Listing 23.8. VaryByCustom.aspx
Note You can detect browser capabilities by using the HttpBrowserCapabilities class exposed by the Request.Browser property. This class includes dozens of properties that enable you to detect the features of the browser being used to request a page. The page contains an <%@ OutputCache %> directive with a VaryByCustom attribute set to the value css. Two different cached versions of the same page are generated: one version for CSS browsers and another version for non-CSS browsers. Specifying the Cache LocationYou can use the Location attribute of the <%@ OutputCache %> directive to specify where a page is cached. This attribute accepts the following values:
By default, when you use Page Output Caching, a page is cached in three locations: the web server, any proxy servers, and the browser. There are situations in which you might need to modify this default behavior. For example, if you are caching private information, then you don't want to cache the information on the web server or any proxy servers. Note When Windows authentication is enabled in the web configuration file (the default), the Cache-Control header is automatically set to the value private, and the setting of the Location attribute is ignored. For example, the page in Listing 23.9 caches a page only on the browser and not on any proxy servers or the web server. The page displays a random number (see Figure 23.4). Figure 23.4. Caching a page on the browser.Listing 23.9. CacheLocation.aspx
If you click the link located at the bottom of the page in Listing 23.9 and request the same page, then the page is retrieved from the browser cache and the same random number is displayed. If you reload the page in your web browser by clicking your browser's Reload button, then the page is reloaded from the web server and a new random number is displayed. The page is cached only in your local browser cache and nowhere else. Note Behind the scenes, the ASP.NET Framework uses the Cache-Control HTTP header to specify where a page is cached. This header is defined in RFC 2616, "Hypertext Transfer ProtocolHTTP/1.1." Creating a Page Output Cache File DependencyYou can create a dependency between a cached page and a file (or set of files) on your hard drive. When the file is modified, the cached page is automatically dropped and regenerated with the next page request. For example, the page in Listing 23.10 displays the contents of an XML file in a GridView. The page is cached until the XML file is modified (see Figure 23.5). Figure 23.5. Caching a page with a file dependency.Listing 23.10. OutputCacheFileDependency.aspx
The page in Listing 23.10 displays the current time. Notice that the time does not change until you modify the Movies.xml XML file. The page in Listing 23.10 uses the Response.AddFileDependency() method to create a dependency between the cached page and a single file on disk. If you need to create a dependency on multiple files, then you can use the AddFileDependencies() method instead. Expiring the Page Output Cache ProgrammaticallyYou can remove a page from the cache programmatically by using the Response.RemoveOutputCacheItem() method. For example, imagine that you are caching a page that displays a list of products. Furthermore, imagine that your website includes a separate page for adding a new product. In that case, you'll want to remove the first page programmatically from the cache when the list of products is updated. The page in Listing 23.11 uses a GridView control to display a list of movies. The page is cached for one hour with an <%@ OutputCache %> directive. Listing 23.11. MovieList.aspx
The page in Listing 23.12 contains a DetailsView control that enables you to add a new movie. When you insert a new movie into the database, the Response.RemoveOutputCacheItem() method is called to remove the MovieList.aspx page from the cache. Because this method accepts only a "virtual absolute" path, the Page.ResolveUrl() method is used to convert the tilde into the application root path. Listing 23.12. AddMovie.aspx
The Response.RemoveOutputCacheItem() method enables you to remove only one page from the cache at a time. If you need to remove multiple pages, then you can create something called a key dependency. A key dependency enables you to create a dependency between one item in the cache and another item. When the second item is removed from the cache, the first item is removed automatically. For example, the page in Listing 23.13 also displays a list of movies. However, the page is cached with a dependency on an item in the cache named Movies. Listing 23.13. MovieListKeyDependency.aspx
The page in Listing 23.14 enables you to add a new movie to the Movies database table. When the new movie is inserted, the Movies item is removed and any pages that are dependent on the Movies item are dropped from the cache automatically. Listing 23.14. AddMovieKeyDependency.aspx
Manipulating the Page Output Cache ProgrammaticallyIf you need more control over how the ASP.NET Framework caches pages, then you can work directly with the HttpCachePolicy class. This class is exposed by the Response.Cache property. The HttpCachePolicy class includes properties and methods that enable you to perform programmatically all the tasks that you can perform with the <%@ OutputCache %> directive. You also can use the methods of this class to manipulate the HTTP cache headers that are sent to proxy servers and browsers. This class supports the following properties:
The HttpCachePolicy class also supports the following methods:
For example, the page in Listing 23.15 programmatically places a page in the output cache. The page is cached on the browser, proxy servers, and web server for 15 seconds. Listing 23.15. ProgramOutputCache.aspx
Clearly, it is more difficult to enable Page Output Caching programmatically than declaratively. You need to call many methods to cache a page in the same way as you can with a single <%@ OutputCache %> directive. However, programmatically manipulating the cache provides you with fine-grained control over the HTTP headers sent to proxy servers and browsers. Creating Page Output Cache ProfilesInstead of configuring Page Output Caching for each page in an application, you can configure Page Output Caching in a web configuration file and apply the settings to multiple pages. You can create something called a Cache Profile. Creating Cache Profiles makes your website easier to manage. For example, the web configuration file in Listing 23.16 contains the definition for a Cache Profile named Cache1Hour that caches a page for one hour. Listing 23.16. Web.Config
The page in Listing 23.17 uses the Cache1Hour profile. This profile is set with the <%@ OutputCache %> directive's CacheProfile attribute. Listing 23.17. OutputCacheProfile.aspx
You can set the same caching properties in a Cache Profile as you can set in an individual page's <%@ OutputCache %> directive. For example, you can set varyByParam, varyByControl, varyByHeader, and even varyByCustom attributes in a Cache Profile. |