WEBSITE

ASP.NET 3.5 : Caching ASP.NET Pages (part 2) - The HttpCachePolicy Class, Caching Multiple Versions of a Page

2/18/2013 6:28:31 PM

2. The HttpCachePolicy Class

The HttpCachePolicy class is a programming interface alternative to using the @OutputCache directive. It provides direct methods to set cache-related HTTP headers, which you could also control to some extent by using the members of the HttpResponse object.

Properties of the HttpCachePolicy Class

Table 3 shows the properties of the HttpCachePolicy class.

Table 3. HttpCachePolicy Class Properties
PropertyDescription
VaryByHeadersGets an object of type HttpCacheVaryByHeaders, representing the list of all HTTP headers that will be used to vary cache output
VaryByParamsGets an object of type HttpCacheVaryByParams, representing the list of parameters received by a GET or POST request that affect caching

When a cached page has several vary-by headers or parameters, a separate version of the page is available for each HTTP header type or parameter name.

Methods of the HttpCachePolicy Class

Table 4 shows the methods of the HttpCachePolicy class.

Table 4. HttpCachePolicy Class Methods
MethodDescription
AddValidationCallbackRegisters a callback function to be used to validate the page output in the server cache before returning it.
AppendCacheExtensionAppends the specified text to the Cache-Control HTTP header. The existing text is not overwritten.
SetAllowResponseInBrowserHistoryWhen this setting is true, the response is available in the browser’s History cache, regardless of the HttpCacheability option set on the server.
SetCacheabilitySets the Cache-Control HTTP header to any of the values taken from the HttpCacheability enumeration type.
SetETagSets the ETag header to the specified string. The ETag header is a unique identifier for a specific version of a document.
SetETagFromFileDependenciesSets the ETag header to a string built by combining and then hashing the last modified date of all the files upon which the page is dependent.
SetExpiresSets the Expires header to an absolute date and time.
SetLastModifiedSets the Last-Modified HTTP header to a particular date and time.
SetLastModifiedFromFileDependenciesSets the Last-Modified HTTP header to the most recent timestamps of the files upon which the page is dependent.
SetMaxAgeSets the max-age attribute on the Cache-Control header to the specified value. The sliding period cannot exceed one year.
SetNoServerCachingDisables server output caching for the current response.
SetNoStoreSets the Cache-Control: no-store directive.
SetNoTransformsSets the Cache-Control: no-transforms directive.
SetOmitVaryStarIf set to true, causes HttpCachePolicy to ignore the * value in VaryByHeaders. Not supported by ASP.NET 1.x.
SetProxyMaxAgeSets the Cache-Control: s-maxage header.
SetRevalidationSets the Cache-Control header to either must-revalidate or proxy-revalidate.
SetSlidingExpirationSets cache expiration to sliding. When cache expiration is set to sliding, the Cache-Control header is renewed at each response.
SetValidUntilExpiresSpecifies whether the ASP.NET cache should ignore HTTP Cache-Control headers sent by some browsers to evict a page from the cache. If this setting is true, the page stays in the cache until it expires.
SetVaryByCustomSets the Vary HTTP header to the specified text string.

Most methods of the HttpCachePolicy class let you control the values of some HTTP headers that relate to the browser cache. The AddValidationCallback method, on the other hand, provides a mechanism to programmatically check the validity of page output in the server cache before it is returned from the cache.

Server Cache-Validation Callback

Before the response is served from the ASP.NET cache, all registered handlers are given a chance to verify the validity of the cached page. If at least one handler marks the cached page as invalid, the entry is removed from the cache and the request is served as if it were never cached. The signature of the callback function looks like this:

public delegate void HttpCacheValidateHandler(
    HttpContext context,
    object data,
    ref HttpValidationStatus validationStatus
);

The first argument denotes the context of the current request, whereas the second argument is any user-defined data the application needs to pass to the handler. Finally, the third argument is a reference to a value from the HttpValidationStatus enumeration. The callback sets this value to indicate the result of the validation. Acceptable values are IgnoreThisRequest, Invalid, and Valid. In the case of IgnoreThisRequest, the cached resource is not invalidated but the request is served as if no response was ever cached. If the return value is Invalid, the cached page is not used and gets invalidated. Finally, if the return value is Valid, the cached response is used to serve the request.

3. Caching Multiple Versions of a Page

Depending on the application context from which a certain page is invoked, the page might generate different results. The same page can be called to operate with different parameters, can be configured using different HTTP headers, can produce different output based on the requesting browser, and so forth.

ASP.NET allows you to cache multiple versions of a page response; you can distinguish versions by GET and POST parameters, HTTP headers, browser type, custom strings, and control properties.

Vary By Parameters

To vary output caching by parameters, you can use either the VaryByParam attribute of the @OutputCache directive or the VaryByParams property on the HttpCachePolicy class. If you proceed declaratively, use the following syntax:

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

Note that the VaryByParam attribute is mandatory; if you don’t want to specify a parameter to vary cached content, set the value to None. If you want to vary the output by all parameters, set the attribute to *. When the VaryByParam attribute is set to multiple parameters, the output cache contains a different version of the requested document for each specified parameter. Multiple parameters are separated by a semicolon. Valid parameters to use are items specified on the GET query string or parameters set in the body of a POST command.

If you want to use the HttpCachePolicy class to define caching parameters, first set the expiration and the cacheability of the page using the SetExpires and SetCacheability methods. Next, set the VaryByParams property as shown here:

Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.VaryByParams["employeeid;lastname"] = true;

This code snippet shows how to vary page output based on the employee ID and the last name properties. Note that the Cache property on the HttpResponse class is just an instance of the HttpCachePolicy type.

Dealing with Postback Pages

Most ASP.NET pages do postbacks. The page in Figure 1 (sqldepoutputcache.aspx) is no exception. The page has two key features: it is dependent on changes to the Customers table in the Northwind database, and it has a cache duration of 30 seconds. Furthermore, the drop-down list (named Countries) has auto-postback functionality and places a POST request for the same page whenever you change the selection.

Figure 1. To properly cache pages that post back, you need to vary them by one or more parameters.

With VaryByParam set to None, you’ll wait 30 seconds (or whatever the cache duration is) to have your country selection processed. It is a bit frustrating: no matter which selection you make, it is blissfully ignored and the same page is displayed. Worse yet, if you test the page under the Visual Studio .NET Web Development server, after a couple of attempts you get a “page not found” error. If you test the page under IIS, you are repeatedly served the same page response, regardless of the selection made.

Two points clearly emerge from this discussion. First, pages with static content are a better fit for caching than interactive pages. Second, the postback mechanism returns a bunch of form parameters. You need to vary the cached copies of the page by the most critical of them. The sample page in Figure 16-7 has a few hidden fields (try snooping in its HTML source), such as __VIEWSTATE and __LASTFOCUS, and the drop-down list. Varying by view state makes no sense at all, but varying by the selected countries is exactly what we need:

<%@ OutputCache VaryByParam="Countries" Duration="30"
                SqlDependency="Northwind:Customers" %>

The directive stores each country-specific page for 30 seconds unless a change occurs in the Customers database. In such a case, all the cached versions of the page will be invalidated.

The bottom line is that enabling page output caching might not be painless for interactive pages. It is free of pain and charge for relatively static pages like those describing a product, a customer, or some news.

Caution

A cached ASP.NET page is served more quickly than a processed page, but not as quickly as a static HTML page. However, the response time is nearly identical if the ASP.NET page is kernel-cached in IIS 6.0. Unfortunately, IIS 6.0 doesn’t store in its kernel-level cache ASP.NET pages requested via a POST verb and, more importantly, pages with VaryByParam or VaryByHeader. In the end, postback pages have very few chances to be cached in the IIS kernel. They are cached in the ASP.NET Cache, in downstream caching servers, or both.


Vary By Headers

The VaryByHeader attribute and the HttpCachePolicy’s VaryByHeaders property allow you to cache multiple versions of a page, according to the value of one or more HTTP headers that you specify.

If you want to cache pages by multiple headers, include a semicolon-delimited list of header names. If you want to cache a different version of the page for each different header value, set the VaryByHeader attribute to an asterisk *. For example, the following declaration caches for one-minute pages based on the language accepted by the browser. Each language will have a different cached copy of the page output.

<%@ OutputCache Duration="60" VaryByParam="None"
    VaryByHeader="Accept-Language" %>

If you opt for a programmatic approach, here’s the code to use that leverages the VaryByHeaders property of the HttpCachePolicy class:

Response.Cache.VaryByHeaders["Accept-Language"] = true;

If you want to programmatically vary the pages in the cache by all HTTP header names, use the VaryByUnspecifiedParameters method of the HttpCacheVaryByHeaders class:

HttpCacheVaryByHeaders.VaryByUnspecifiedParameters();

The preceding code is equivalent to using the asterisk with the VaryByHeader attribute.

Vary By Custom Strings

The VaryByCustom attribute in the @OutputCache directive allows you to vary the versions of page output by the value of a custom string. The string you assign to the VaryByCustom attribute simply represents the description of the algorithm employed to vary page outputs. The string is then passed to the GetVaryByCustomString method, if any, in the global.asax file. The method takes the string and returns another string that is specific to the request. Let’s examine a concrete example—varying pages by the type of device that requests the page. You use, say, the string device with the VaryByCustom attribute:

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

Next, you add your application-specific GetVaryByCustomString method in the global.asax file. Here’s a possible implementation:

public override string GetVaryByCustomString(HttpContext context, string custom)
{
    if (custom == "device")
        return context.Request.Browser.Type;
    return base.GetVaryByCustomString(context, custom);
}


					  

The output of the page is varied by user agent string. You can use any other custom information as long as the information is available through the HttpContext class. You can’t use information that is known only when the page is loaded, such as the theme. Custom information gathered by a custom HTTP module might be used if the HTTP module parks the information in the Items collection of the HttpContext object, and as long as the HTTP module is triggered before the request to resolve the page output cache is made.

Nicely enough, the feature described above—varying pages by user agent strings—is natively available since ASP.NET 1.0. The only difference is that it uses the keyword browser instead of device. In other words, the following code is perfectly acceptable and leverages the implementation of GetVaryByCustomString on the base HttpApplication class:

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

You use the SetVaryByCustom method on the HttpCachePolicy class if you don’t like the declarative approach:

Response.Cache.SetVaryByCustom("browser");
Other  
 
Top 10
Review : Sigma 24mm f/1.4 DG HSM Art
Review : Canon EF11-24mm f/4L USM
Review : Creative Sound Blaster Roar 2
Review : Philips Fidelio M2L
Review : Alienware 17 - Dell's Alienware laptops
Review Smartwatch : Wellograph
Review : Xiaomi Redmi 2
Extending LINQ to Objects : Writing a Single Element Operator (part 2) - Building the RandomElement Operator
Extending LINQ to Objects : Writing a Single Element Operator (part 1) - Building Our Own Last Operator
3 Tips for Maintaining Your Cell Phone Battery (part 2) - Discharge Smart, Use Smart
REVIEW
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
VIDEO TUTORIAL
- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
Popular Tags
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Exchange Server Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe Photoshop CorelDRAW X5 CorelDraw 10 windows Phone 7 windows Phone 8 Iphone