Using Page Output Caching


You can use page output caching to dramatically improve the performance of your Web site. Instead of executing a page each time the page is requested , you can cache the output of the page and send the cached copy to satisfy browser requests .

Imagine, for example, that your site includes a page that displays product information retrieved from a database table. By default, every time someone requests the product page, the page must be executed and the information must be retrieved from the database. If you enable page output caching, however, the page is executed only once, and the information is retrieved from the database only once. This means less work both for your Web application and for your database server.

To enable output caching for a page, include the following page directive in the page:

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

This directive causes the output of the page to be cached for 60 seconds.

The page in Listing 17.1, for example, displays the current time. The page also includes an OutputCache directive that caches the output of the page for 10 seconds. If you repeatedly refresh the page, you'll notice that the time is updated only once every 10 seconds.

Listing 17.1 TimeCache.aspx
 <%@ OutputCache Duration="10" VaryByParam="none" %> <html> <head><title>TimeCache.aspx</title></head> <body> At the tone, the time will be: <%= Now() %> </body> </html> 

The C# version of this code can be found on the CD-ROM.

You can also cache the output of a page that retrieves data from a database. For example, Listing 17.2 contains a product page that displays information on a particular product retrieved from the Northwind database. This page is cached for 5 minutes.

Listing 17.2 ProductPage.aspx
 <%@ OutputCache Duration="300" VaryByParam="none" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <Script Runat="Server"> Sub Page_Load   Dim conNorthwind As SqlConnection   Dim strSelect As String   Dim cmdSelect As SqlCommand   Dim dtrProducts As SqlDataReader   conNorthwind = New SqlConnection( "Server=Localhost;UID=sa;PWD=secret;Database=Northwind" )   strselect = "Select * From Products Where ProductID=1"   cmdSelect = New SqlCommand( strSelect, conNorthwind )   conNorthwind.Open()     dgrdProducts.DataSource = cmdSelect.ExecuteReader( CommandBehavior.SingleRow )     dgrdProducts.DataBind()   conNorthwind.Close End Sub </Script> <html> <head><title>ProductPage.aspx</title></head> <body> <asp:DataGrid   ID="dgrdProducts"   CellPadding="10"   Runat="Server" /> <hr> <small>Last Updated: <%=Now%></small> </body> </html> 

The C# version of this code can be found on the CD-ROM.

The OutputCache directive at the top of the page in Listing 17.2 results in the page being cached for 5 minutes. The page also is regenerated if its source is modified.

CAUTION

You are not guaranteed that items will remain in the page output cache. If system resources get low, the ASP.NET Framework starts dumping items from the cache.


Varying Cache Contents by Parameter

The OutputCache directive has a second attribute that indicates how a page should be cached when a request for a page contains parameters (either query string parameters or form field parameters). This attribute can accept either a semicolon-delimited list of parameters or one of the following special values:

  • none ” Indicates that different cached versions of a page should not be created when the page is requested with different parameters.

  • * ” Indicates that different cached versions of a page should be created whenever the page is requested with different parameters.

The VaryByParam attribute is particularly useful when you need to display different content on a page depending on the value of a query string parameter.

For example, in the preceding section, you used the OutputCache page directive to cache the output of a page that retrieves product information from a database table. The page works fine as long as you want to display information for only one product. Typically, however, you want to create a page that displays information on different products depending on the value of a query string parameter passed to the page.

Consider the page in Listing 17.3. This page displays information on different products depending on the value of the PID query string variable.

Listing 17.3 ProductPageByParam.aspx
 <%@ OutputCache Duration="300" VaryByParam="none" %> <%@ Import Namespace="System.Data.SqlClient" %> <Script Runat="Server"> Sub Page_Load( s As Object, e As EventArgs )   Dim strProductID As String   Dim conNorthwind As SqlConnection   Dim strSelect As String   Dim cmdSelect As SqlCommand   Dim dtrProducts As SqlDataReader   strProductID = Request.Params( "PID" )   If strProductID = Nothing Then     strProductID = "1"   End If   conNorthwind = New SqlConnection( "Server=Localhost;UID=sa;PWD=secret;Database=Northwind" )   strSelect = "Select * From Products Where ProductID=" & strProductID   cmdSelect = New SqlCommand( strSelect, conNorthwind )   conNorthwind.Open     dgrdProducts.DataSource = cmdSelect.ExecuteReader()     dgrdProducts.DataBind()   conNorthwind.Close End Sub </Script> <html> <head><title>ProductPageByParam.aspx</title></head> <body> <asp:DataGrid   ID="dgrdProducts"   CellPadding="10"   Runat="Server" /> <hr> <small>Last Updated: <%=Now%></small> </body> </html> 

The C# version of this code can be found on the CD-ROM.

The value of the PID query string variable is grabbed in the Page_Load subroutine and assigned to a variable named strProductID . If PID doesn't have a value, the strProductID variable defaults to the value 1. You use the strProductID variable to retrieve information on a specific product in the Products database table.

In Listing 17.3, the VaryByParam attribute is assigned the value none . If you request the page in Listing 17.3 without including a PID in the query string, the page displays the information for the product with a product ID of 1. The OutputCache directive causes the page to be cached for 300 seconds.

If you subsequently request the page by supplying a PID, you'll still receive the same cached page as before. Regardless of the PID that you supply, the page will continue to display the content for the product with the PID of 1.

Since the VaryByParam attribute is assigned the value none , any query string parameter passed to the page is ignored. This isn't good since you want to display different product information with the page depending on the value of the PID parameter.

There are two ways around this problem. You can indicate that you want a different cached version of the page whenever different parameters are passed to the page by declaring the OutputCache directive like this:

 
 <%@ OutputCache Duration="300" VaryByParam="*" %> 

This directive indicates that different cached versions of the page should be created whenever a different parameter is passed to the page. So both of the following requests would generate different cached pages:

http://Localhost/ProductPageByParm.aspx?PID=4

http://Localhost/ProductPageByParm.aspx?username=bob

 
 <%@ OutputCache Duration="300" VaryByParam="PID" %> 

This directive stores different cached versions of a page depending on the value of the PID query string parameter. If you request the page with a PID of 1, and then request the page with a PID of 4, different cached versions of the page are stored.

The modified product page is contained in Listing 17.4.

Listing 17.4 ProductPageByParamCache.aspx
 <%@ OutputCache Duration="300" VaryByParam="PID" %> <%@ Import Namespace="System.Data.SqlClient" %> <Script Runat="Server"> Sub Page_Load( s As Object, e As EventArgs )   Dim strProductID As String   Dim conNorthwind As SqlConnection   Dim strSelect As String   Dim cmdSelect As SqlCommand   Dim dtrProducts As SqlDataReader   strProductID = Request.Params( "PID" )   If strProductID = Nothing Then     strProductID = "1"   End If   conNorthwind = New SqlConnection( "Server=Localhost;UID=sa;PWD=secret;Database=Northwind" )   strSelect = "Select * From Products Where ProductID=" & strProductID   cmdSelect = New SqlCommand( strSelect, conNorthwind )   conNorthwind.Open     dgrdProducts.DataSource = cmdSelect.ExecuteReader()     dgrdProducts.DataBind()   conNorthwind.Close End Sub </Script> <html> <head><title>ProductPageByParamCache.aspx</title></head> <body> <asp:DataGrid   ID="dgrdProducts"   CellPadding="10"   Runat="Server" /> <hr> <small>Last Updated: <%=Now%></small> </body> </html> 

The C# version of this code can be found on the CD-ROM.

You can list more than one parameter in the VaryByParam attribute. You simply need to separate each parameter listed with a semicolon. For example, the following OutputCache directive creates different cached copies of a page depending on the values of the PID and ProductCategory parameters:

 
 <%@ OutputCache Duration="20" VaryByParam="PID;ProductCategory" %> 

Be aware, however, that each cached copy of a page eats away at memory. So, the more versions of a page that you cache, the more server resources are consumed.

Varying Cache Contents by Header

One of the benefits of using the controls in the ASP.NET framework is that many of them can detect the type of browser being used to request a page and display different content appropriate to the capabilities of the browser. However, by default, page output caching defeats a control's capability to display different content for different browsers. Because page output caching stores the output of a page, the very same page is sent to every browser that requests it.

Fortunately, you can find an easy way around this problem. The OutputCache page directive supports a VaryByHeader attribute. You can use this attribute to cache different versions of a page depending on the type of browser that requests the page. Here's how you would use this directive:

 
 <%@ OutputCache Duration="20" VaryByParam="*" VaryByHeader="User-Agent"%> 

The User-Agent header identifies the type of browser being used to request the page. Different types of browsers ”such as Netscape, Internet Explorer, and Opera ”transmit different User-Agent headers when they request a page. Normally, the User-Agent header also includes such information as the version of the browser and type of platform on which the browser is running.

The page in Listing 17.5 illustrates how you use the VaryByHeader attribute. This page displays different content depending on whether it is requested by a Netscape browser or some other type of browser. When the page is requested by a Netscape browser, the page displays blinking text. Otherwise , the page displays the text in a red font (see Figure 17.1).

Listing 17.5 CacheByHeader.aspx
 <%@ OutputCache Duration="300" VaryByParam="*" VaryByHeader="User-Agent"%> <Script Runat="Server"> Dim strBuyOurProducts As String Sub Page_Load   If Request.Browser.Browser = "Netscape" Then     strBuyOurProducts = "<Blink>Buy Our Products!</Blink>"   Else     strBuyOurProducts = "<font color=red>Buy Our Products!</font>"   End If End Sub </Script> <html> <head><title>CacheByHeader.aspx</title></head> <body> <h1><%=strBuyOurProducts %></h1> <hr> <small>Last Updated: <%=Now%></small> </body> </html> 

The C# version of this code can be found on the CD-ROM.

Figure 17.1. Using the CacheByHeader attribute.

graphics/17fig01.jpg

If you launch both Netscape and Internet Explorer browsers on your computer and request the page in Listing 17.5, different content is displayed. Note that different copies of the page are cached not only when different types of browsers request the page, but also when different versions of the same browser request the page. Any variation in the User-Agent header results in a different version of the page being cached.

NOTE

See the next section for a way to make the output cache less sensitive to minor differences in browser types.


You also can use the VaryByHeader attribute to create different cached versions of a page depending on other headers, such as Referrer , Host , and Accept-Language headers.

You can use the page in Listing 17.6 to view all the headers that you can use from the ServerVariables collection (see Figure 17.2).

Listing 17.6 ServerVariables.aspx
 <Script Runat="Server"> Sub Page_Load   Dim strHeader As String   For each strHeader in Request.ServerVariables     lblOutput.Text &= "<li>" & strHeader & "=" & Request( strHeader )   Next End Sub </Script> <html> <head><title>ServerVariables.aspx</title></head> <body> <asp:Label   ID="lblOutput"   Runat="Server" /> </body> </html> 

The C# version of this code can be found on the CD-ROM.

Figure 17.2. The ServerVariables collection.

graphics/17fig02.jpg

Varying the Cache Contents by a Custom String

The OutputCache directive supports an additional attribute named VaryByCustom . This attribute enables you to control the sensitivity of page output caching.

In the preceding section, you used the VaryByHeader attribute with the User-Agent header to cache different versions of a page depending on the browser. One problem with this approach is that the User-Agent header not only varies among different types of browsers, but also typically contains additional information, such as information about the version of the browser and computer platform on which the browser is running.

If you want to make broader distinctions among browsers, you can use the VaryByCustom attribute like this:

 
 <%@ OutputCache Duration="60" VaryByParam="*" VaryByCustom="Browser" %> 

When you use the value Browser with the VaryByCustom attribute, only the browser name and major version information are taken into account when caching the output of a page. So, the same page would be cached for Internet Explorer 5.0 and Internet Explorer 5.5.

You also can supply a custom string to the VaryByCustom attribute. If you supply a custom string, you are responsible for creating a function in the Global.asax file that controls how pages are cached.

NOTE

To learn more information about the Global.asax file, see Chapter 15, "Creating ASP.NET Applications."


Suppose that you want to cache different versions of a page depending on whether the browser requesting the page supports VBScript. To do so, you need to assign a custom string to the VaryByCustom attribute. Listing 17.7 illustrates the proper method of assigning a string to the VaryByCustom attribute in the OutputCache directive. (This file is located in the VaryByCustom subdirectory.)

Listing 17.7 VaryByCustom / VaryByCustom.aspx
 <%@ OutputCache Duration="300" VaryByParam="*" VaryByCustom="VBScript" %> <Script Runat="Server"> Sub Page_Load   lblMessage.Text = Request.Browser.VBScript End Sub </Script> <html> <head><title>VaryByCustom.aspx</title></head> <body> <asp:Label   ID="lblMessage"   Runat="Server" /> <hr> Page generated: <%=DateTime.Now %> </body> </html> 

The C# version of this code can be found on the CD-ROM.

Next, you need to add a new function named GetVaryByCustomString to the Global.asax file. This function is included in the Global.asax file in Listing 17.8.

Listing 17.8 VaryByCustom / Global.asax
 <Script Runat="Server"> Overrides Function GetVaryByCustomString( _   objContext As HttpContext, _   strCustom As String ) As String   Return objContext.Request.Browser.VBScript End Function </Script> 

The C# version of this code can be found on the CD-ROM.

CAUTION

The Global.asax file must be located in the application root directory; it doesn't work in a subdirectory.


The GetVaryByCustomString function has two parameters: the current context and the custom string passed by the VaryByCustom attribute. The function returns a string indicating how a page should be cached. In the case of Listing 17.8, the function returns the value True when a browser supports VBScript and False otherwise. The function therefore creates two different cached versions of the page.

NOTE

To determine whether a browser supports VBScript, you can use the HttpBrowserCapabilities class. You can use this class to detect many other features of a browser, such as its name, its major and minor version number, whether it supports Java applets, and so on.


Setting the Cache Location

By default, when you enable page output caching, the page is cached on both the server and client. The page is cached in the server's memory, and the proper headers are sent to the browser requesting the page to cause the browser to create a cached copy.

You can control the exact location where the caching occurs by adding the Location attribute to the OutputCache page directive. The Location attribute can have any one of the following values from the OutputCacheLocation enumeration:

  • Any ” This is the default value. The page should be cached at any location, including the server, any downstream servers, and the browser.

  • Client ” The output of the page should be cached only on the browser.

  • Downstream ” The output of the page should be cached only on a downstream server.

  • None ” No page caching should be performed.

  • Server ” The page should be cached only on the server.

If you want to cache the output of a page only on the browser and not on the server, for example, you would use the following OutputCache directive:

 
 <%@ OutputCache Duration="600" VaryByParam="*" Location="Client" %> 

Be aware, however, that browser caching is browser-dependent.

Working with the HttpCachePolicy Class

Behind the scenes, page output caching is handled by the HttpCachePolicy class. If you want more fine-grained control over the caching behavior of a page, you can directly call the methods of this class.

The two most important methods of this class are the SetExpires() and SetCacheability() methods. The SetExpires() method indicates an absolute date and time when a page expires , and the SetCacheability() method indicates how the page should be cached. The SetCacheability() method accepts any of the following values from the HttpCacheability enumeration:

  • NoCache ” Prevents any page caching with the Cache-Control:no-cache header.

  • Private ” Indicates that the page should not be cached by proxy servers, but can be cached by browsers (this is the default value).

  • Public ” Indicates that the page can be cached by proxy servers and browsers.

  • Server ” Indicates that the page should only be cached on the server.

For example, the page in Listing 17.9 uses the methods of the HttpCachePolicy class to cache a page on the server until 12/25/2005. (Most likely, the page will be dumped from the cache much earlier than that.)

Listing 17.9 HttpCachePolicy.aspx
 <Script Runat="Server"> Sub Page_Load   Response.Cache.SetExpires( #12/25/2005# )   Response.Cache.SetCacheability( HttpCacheability.Server ) End Sub </Script> <html> <head><title>HttpCachePolicy.aspx</title></head> <body> At the tone, the time will be: <%=Now() %> </body> </html> 

The C# version of this code can be found on the CD-ROM.



ASP.NET Unleashed
ASP.NET 4 Unleashed
ISBN: 0672331128
EAN: 2147483647
Year: 2003
Pages: 263

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net