In the previous section of this chapter, you learned how to cache the entire output of a page. In this section, you learn how to take advantage of Partial Page Caching to cache particular regions of a page. Partial Page Caching makes sense when a page contains both dynamic and static content. For example, you might want to cache a set of database records displayed in a page, but not cache a random list of news items displayed in the same page. In this section, you learn about two methods for enabling Partial Page Caching. You can use post-cache substitution to cache an entire page except for a particular region. You can use User Controls to cache particular regions in a page, but not the entire page. Using Post-Cache SubstitutionIn some cases, you might want to cache an entire page except for one small area. For example, you might want to display the current username dynamically at the top of a page, but cache the remainder of a page. In these cases, you can take advantage of a feature of the ASP.NET Framework called post-cache substitution. Post-cache substitution is used internally by the AdRotator control. Even when you use Page Output Caching to cache a page that contains an AdRotator control, the content rendered by the AdRotator control is not cached. You can use post-cache substitution either declaratively or programmatically. If you want to use post-cache substitution declaratively, then you can use the ASP.NET Substitution control. For example, the page in Listing 23.18 uses the Substitution control to display the current time on a page that has been output cached (see Figure 23.6). Figure 23.6. Using the Substitution control.Listing 23.18. SubstitutionControl.aspx
In Listing 23.18, the time is displayed twice. The time displayed in the body of the page is output cached. The time displayed by the Substitution control is not cached. The Substitution control has one important property: MethodName. The MethodName property accepts the name of a method defined in the page. The method must be a shared (static) method because an instance of the class is not created when the page is output cached. Alternatively, you can use post-cache substitution programmatically by using the Response.WriteSubstitution() method. This method is illustrated in the page in Listing 23.19. Listing 23.19. ShowWriteSubstitution.aspx
There are two advantages to using the WriteSubstitution() method. First, the method referenced by the WriteSubstitution() method does not have to be a method of the current class. The method can be either an instance or shared method on any class. The second advantage of the WriteSubstitution() method is that you can use it within a custom control to perform post-cache substitutions. For example, the NewsRotator control in Listing 23.20 uses the WriteSubstitution() method when displaying a random news item. If you use this control in a page that has been output cached, the NewsRotator control continues to display news items randomly. Listing 23.20. NewsRotator.vb
Note Building custom controls is discussed in detail in Chapter 31, "Building Custom Controls." The CD that accompanies this book includes a page named ShowNewsRotator.aspx. If you open this page, all the content of the page is cached except for the random news item displayed by the NewsRotator control (see Figure 23.7). Figure 23.7. Displaying dynamic news items in a cached page.When you use post-cache substitution (declaratively or programmatically) then caching no longer happens beyond the web server. Using post-cache substitution causes a Cache-Control:no-cache HTTP header to be included in the HTTP response, which disables caching on proxy servers and browsers. This limitation is understandable because the substitution content must be generated dynamically with each page request. Caching with a User ControlUsing post-cache substitution is appropriate only when working with a string of text or HTML. If you need to perform more complex partial page caching, then you should take advantage of User Controls. You can cache the rendered contents of a User Control in memory in the same way as you can cache an ASP.NET page. When you add an <%@ OutputCache %> directive to a User Control, the rendered output of the User Control is cached. Note When you cache a User Control, the content is cached on the web server and not on any proxy servers or web browsers. When a web browser or proxy server caches a page, it always caches an entire page. For example, the Movies User Control in Listing 23.21 displays all the rows from the Movies database table. Furthermore, it includes an OutputCache directive, which causes the contents of the User Control to be cached in memory for a maximum of 10 minutes (600 seconds). Listing 23.21. Movies.ascx
The User Control in Listing 23.21 displays the records from the Movies database table with a GridView control. It also displays the current time. Because the control includes an OutputCache directive, the entire rendered output of the control is cached in memory. The page in Listing 23.22 includes the Movies User Control in the body of the page. It also displays the current time at the top of the page. When you refresh the page, the time displayed by the Movies control changes, but not the time displayed in the body of the page (see Figure 23.8). Figure 23.8. Caching the output of a User Control.Listing 23.22. ShowUserControlCache.aspx
You can use the following attributes with an <%@ OutputCache %> directive declared in a User Control:
Because each User Control that you add to a page can have different caching policies, and because you can nest User Controls with different caching policies, you can build pages that have fiendishly complex caching policies. There is nothing wrong with doing this. In fact, you should take advantage of this caching functionality whenever possible to improve the performance of your applications. Warning Be careful when setting properties of a cached User Control. If you attempt to set the property of a User Control programmatically when the content of the control is served from the cache, you get a NullReference exception. Before setting a property of a cached control, first check whether the control actually exists like this: If Not IsNothing(myControl) Then myControl.SomeProperty = "some value" End If Sharing a User Control Output CacheBy default, instances of the same User Control located on different pages do not share the same cache. For example, if you add the same Movies User Control to more than one page, then the contents of each user control is cached separately. If you want to cache the same User Control content across multiple pages, then you need to include the Shared attribute when adding the <%@ OutputCache %> directive to a User Control. For example, the modified Movies User Control in Listing 23.23 includes the Shared attribute. Listing 23.23. SharedMovies.ascx
Using the Shared attribute is almost always a good idea. You can save a significant amount of server memory by taking advantage of this attribute. Manipulating a User Control Cache ProgrammaticallyWhen you include an <%@ OutputCache %> directive in a User Control, you can modify programmatically how the User Control is cached. The User Control CachePolicy property exposes an instance of the ControlCachePolicy class, which supports the following properties:
The ControlCachePolicy class also supports the following methods:
For example, the User Control in Listing 23.24 uses a sliding expiration policy of one minute. When you specify a sliding expiration policy, a User Control is cached just as long as you continue to request the User Control within the specified interval of time. Listing 23.24. SlidingUserCache.ascx
The CD that accompanies this book includes a page named ShowSlidingUserCache.aspx, which contains the SlidingUserCache control. If you keep requesting this page, and do not let more than one minute pass between requests, then the User Control isn't dropped from the cache. Creating a User Control Cache File DependencyYou can use the CacheControlPolicy.Dependency property to create a dependency between a cached User Control and a file (or set of files) on the file system. When the file is modified, the User Control is dropped from the cache automatically and reloaded with the next page request. For example, the User Control in Listing 23.25 displays all the movies from the Movies.xml file in a GridView control. Notice that the User Control includes a Page_Load() handler that creates a dependency on the Movies.xml file. Listing 23.25. MovieFileDependency.ascx
The CD that accompanies this book includes a page named ShowMovieFileDependency, which displays the MovieFileDependency User Control (see Figure 23.9). If you open the page, then the User Control is automatically cached until you modify the Movies.xml file. Figure 23.9. Displaying a User Control with a file dependency.Caching Dynamically Loaded User ControlsYou can load a User Control dynamically by using the Page.LoadControl() method. You can cache dynamically loaded User Controls in the same way that you can cache User Controls declared in a page. If a User Control includes an <%@ OutputCache %> directive, then the User Control will be cached regardless of whether the control was added to a page declaratively or programmatically. However, you need to be aware that when a cached User Control is loaded dynamically, the ASP.NET Framework automatically wraps the User Control in an instance of the PartialCachingControl class. Therefore, you need to cast the control returned by the Page.LoadControl() method to an instance of the PartialCachingControl class. For example, the page in Listing 23.26 dynamically adds the Movies User Control in its Page_Load() event handler. The Page_Load() method overrides the default cache duration specified in the User Control's <%@ OutputCache %> directive. The cache duration is changed to 15 seconds (see Figure 23.10). Figure 23.10. Programmatically caching a User Control.Listing 23.26. ShowDynamicUserControl.aspx
In Listing 23.26, the default cache duration is modified by modifying the PartialCachingControl's CachePolicy property. This property returns an instance of the same ControlCachePolicy class described in the two previous sections of this chapter. You can refer to the User Control contained with an instance of the PartialCachingControl class by using the class's CachedControl property. Normally, this property returns the value Nothing (null) because when the User Control is cached, it is never actually created. |