1367 Using Partial Page Caching NOTE When you cache a User Control, the content is cached on the web server and not on any proxy servers or web browsers.. Furthermore, it includes an Out
Trang 1LISTING 29.19 ShowWriteSubstitution.aspx
<%@ Page Language=”C#” %>
<%@ OutputCache Duration=”15” VaryByParam=”none” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<script runat=”server”>
public static string GetTime(HttpContext context)
{
return DateTime.Now.ToString(“T”);
}
</script>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head id=”Head1” runat=”server”>
<title>Show WriteSubstitution</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
The cached time is: <%= DateTime.Now.ToString(“T”) %>
<hr />
The substitution time is:
<% Response.WriteSubstitution(GetTime); %>
</div>
</form>
</body>
</html>
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 29.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
Trang 21365
Using Partial Page Caching
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections.Generic;
namespace myControls
{
public class NewsRotator : WebControl
{
public static string GetNews(HttpContext context)
{
List<String> news = new List<string>();
news.Add(“Martians attack!”);
news.Add(“Moon collides with earth!”);
news.Add(“Life on Jupiter!”);
Random rnd = new Random();
return news[rnd.Next(news.Count)];
}
protected override void RenderContents(HtmlTextWriter writer)
{
Context.Response.WriteSubstitution(GetNews);
}
}
}
NOTE
Building custom controls is discussed in detail in Chapter 36, “Building Custom
Controls.”
The book’s website 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 29.7)
Trang 3When you use post-cache substitution (declaratively or programmatically) 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 Control
Using 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, you should take
advan-tage 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
FIGURE 29.7 Displaying dynamic news items in a cached page
Trang 41367
Using Partial Page Caching
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 29.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 29.21 Movies.ascx
<%@ Control Language=”C#” ClassName=”Movies” %>
<%@ OutputCache Duration=”600” VaryByParam=”none” %>
User Control Time:
<%= DateTime.Now.ToString(“T”) %>
<asp:GridView
id=”grdMovies”
DataSourceID=”srcMovies”
Runat=”server” />
<asp:SqlDataSource
id=”srcMovies”
ConnectionString=”<%$ ConnectionStrings:Movies %>”
SelectCommand=”SELECT Title,Director FROM Movies”
Runat=”server” />
The User Control in Listing 29.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 29.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 29.8)
Trang 5LISTING 29.22 ShowUserControlCache.aspx
<%@ Page Language=”C#” %>
<%@ Register TagPrefix=”user” TagName=”Movies” Src=”~/Movies.ascx” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.1//EN”
“http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head id=”Head1” runat=”server”>
<title>Show User Control Cache</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
Page Time:
<%= DateTime.Now.ToString(“T”) %>
<hr />
FIGURE 29.8 Caching the output of a User Control
Trang 61369
Using Partial Page Caching
</div>
</form>
</body>
</html>
You can use the following attributes with an <%@ OutputCache %> directive declared in a
User Control:
Control is cached
multiple pages
depending on the values of one or more query string or form parameters You can
specify multiple parameters by supplying a semicolon-delimited list of query string
or form parameter names
depending on the value of a control You can specify multiple controls by supplying
a semicolon-delimited list of control IDs
poli-cy (You also can supply the special value browser, which causes different cached
ver-sions of the control to be created when the type and major version of the browser
differs.)
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;
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 (myControl != null)
myControl.SomeProperty = “some value”;
Trang 7Sharing a User Control Output Cache
By 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, the contents of each user control is cached separately
If you want to cache the same User Control content across multiple pages, 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 29.23 includes the
Shared attribute
LISTING 29.23 SharedMovies.ascx
<%@ Control Language=”C#” ClassName=”SharedMovies” %>
<%@ OutputCache Duration=”600” VaryByParam=”none” Shared=”true” %>
User Control Time:
<%= DateTime.Now.ToString() %>
<asp:GridView
id=”grdMovies”
DataSourceID=”srcMovies”
Runat=”server” />
<asp:SqlDataSource
id=”srcMovies”
ConnectionString=”<%$ ConnectionStrings:Movies %>”
SelectCommand=”SELECT Title,Director FROM Movies”
Runat=”server” />
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 Programmatically
When 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:
Trang 81371
Using Partial Page Caching
depending on the value of a control
depending on the value of a query string or form parameter
The ControlCachePolicy class also supports the following methods:
policy (You also can supply the special value browser, which causes different cached
versions of the control to be created when the type and major version of the browser
differs.)
For example, the User Control in Listing 29.24 uses a sliding expiration policy of 1
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 29.24 SlidingUserCache.ascx
<%@ Control Language=”C#” ClassName=”SlidingUserCache” %>
<%@ OutputCache Duration=”10” VaryByParam=”none” %>
<script runat=”server”>
void Page_Load()
{
CachePolicy.SetSlidingExpiration(true);
CachePolicy.Duration = TimeSpan.FromMinutes(1);
}
</script>
User Control Time:
<%= DateTime.Now.ToString(“T”) %>
The book’s website includes a page named ShowSlidingUserCache.aspx, which contains
the SlidingUserCache control If you keep requesting this page, and do not let more than
1 minute pass between requests, the User Control isn’t dropped from the cache
Trang 9Creating a User Control Cache File Dependency
You 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 29.25 displays all the movies from the
Movies.xml file in a GridView control The User Control includes a Page_Load() handler
that creates a dependency on the Movies.xml file
LISTING 29.25 MovieFileDependency.ascx
<%@ Control Language=”C#” ClassName=”MovieFileDependency” %>
<%@ OutputCache Duration=”9999” VaryByParam=”none” %>
<script runat=”server”>
void Page_Load()
{
CacheDependency depend = new CacheDependency(MapPath(“~/Movies.xml”));
this.CachePolicy.Dependency = depend;
}
</script>
User Control Time:
<%= DateTime.Now.ToString(“T”) %>
<hr />
<asp:GridView
id=”grdMovies”
DataSourceID=”srcMovies”
Runat=”server” />
<asp:XmlDataSource
id=”srcMovies”
DataFile=”Movies.xml”
Runat=”server” />
The code download on the website that accompanies this book includes a page named
ShowMovieFileDependency, which displays the MovieFileDependency User Control (see
Figure 29.9) If you open the page, the User Control is automatically cached until you
Trang 101373
Using Partial Page Caching
Caching Dynamically Loaded User Controls
You 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,
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,
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 29.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 29.10)
FIGURE 29.9 Displaying a User Control with a file dependency