Advanced ASP.NET : Output Caching

2/15/2011 8:06:37 PM
With output caching, the final rendered HTML of the page is cached. When the same page is requested again, the control objects are not created, the page life cycle doesn't start, and none of your code executes. Instead, the cached HTML is served. Clearly, output caching gets the theoretical maximum performance increase, because all the overhead of your code is sidestepped.

To see output caching in action, you can create a simple page that displays the current time of day. Figure 1 shows this page.

Figure 1. Displaying the time a page is served

The code for this task is elementary:

Public Partial Class OutputCaching
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
lblDate.Text = "The time is now:<br />"
lblDate.Text &= DateTime.Now.ToString()
End Sub

End Class

You can cache an ASP.NET page in two ways. The most common approach is to insert the OutputCache directive at the top of your .aspx file, just below the Page directive, as shown here:

<%@ OutputCache Duration="20" VaryByParam="None" %>

The Duration attribute instructs ASP.NET to cache the page for 20 seconds. The VaryByParam attribute is also required—but you'll learn about its effect later in the "Caching and the Query String" section.

When you run the test page, you'll discover some interesting behavior. The first time you access the page, you will see the current time displayed. If you refresh the page a short time later, however, the page will not be updated. Instead, ASP.NET will automatically send the cached HTML output to you, until it expires in 20 seconds. If ASP.NET receives a request after the cached page has expired, ASP.NET will run the page code again, generate a new cached copy of the HTML output, and use that for the next 20 seconds.

Twenty seconds may seem like a trivial amount of time, but in a high-volume site, it can make a dramatic difference. For example, you might cache a page that provides a list of products from a catalog. By caching the page for 20 seconds, you limit database access for this page to three operations per minute. Without caching, the page will try to connect to the database once for each client and could easily make dozens of requests in the course of 20 seconds.

Of course, just because you request that a page should be stored for 20 seconds doesn't mean that it actually will be. The page could be evicted from the cache early if the system finds that memory is becoming scarce. This allows you to use caching freely, without worrying too much about hampering your application by using up vital memory.

When you recompile a cached page, ASP.NET will automatically remove the page from the cache. This prevents problems where a page isn't properly updated, because the older, cached version is being used. However, you might still want to disable caching while testing your application. Otherwise, you may have trouble using variable watches, breakpoints, and other debugging techniques, because your code will not be executed if a cached copy of the page is available.

1. Caching on the Client Side

Another option is to cache the page exclusively on the client side. In this case, the browser stores a copy and will automatically use this page if the client browses back to the page or retypes the page's URL. However, if the user clicks the Refresh button, the cached copy will be abandoned, and the page will be rerequested from the server, which will run the appropriate page code once again. You can cache a page on the client side using the Location attribute in the OutputCache directive, which specifies a value from the System.Web.UI.OutputCacheLocation enumeration, as shown here:

<%@ OutputCache Duration="20" VaryByParam="None" Location="Client" %>

Client-side caching is less common than server-side caching. Because the page is still re-created for every separate user, it won't reduce code execution or database access nearly as dramatically as server-side caching (which shares a single cached copy among all users). However, client-side caching can be a useful technique if your cached page uses some sort of personalized data. For example, imagine a page that displays a user-specific greeting. In this situation, server-side caching isn't ideal. The problem is that the page will be created just once and reused for all clients, ensuring that most will receive the wrong greeting. In this situation, you can either use fragment caching to cache the generic portion of the page or use client-side caching to store a user-specific version on each client's computer.

2. Caching and the Query String

One of the main considerations in caching is deciding when a page can be reused and when information must be accurate up to the latest second. Developers, with their love of instant gratification (and lack of patience), generally tend to overemphasize the importance of real-time information. You can usually use caching to efficiently reuse slightly stale data without a problem and with a considerable performance improvement.

Of course, sometimes information needs to be dynamic. One example is if the page uses information from the current user's session to tailor the user interface. In this case, full page caching just isn't appropriate, because the same page can't be reused for requests from different users (although fragment caching may help). Another example is if the page is receiving information from another page through the query string. In this case, the page is too dynamic to cache—or is it?

The current example sets the VaryByParam attribute on the OutputCache directive to None, which effectively tells ASP.NET that you need to store only one copy of the cached page, which is suitable for all scenarios. If the request for this page adds query string arguments to the URL, it makes no difference—ASP.NET will always reuse the same output until it expires. You can test this by adding a query string parameter manually in the browser window. For example, try tacking ?a=b on to the end of your URL. The cached output is still used.

Based on this experiment, you might assume that output caching isn't suitable for pages that use query string arguments. But ASP.NET actually provides another option. You can set the VaryByParam attribute to * to indicate that the page uses the query string and to instruct ASP.NET to cache separate copies of the page for different query string arguments:

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

Now when you request the page with additional query string information, ASP.NET will examine the query string. If the string matches a previous request and a cached copy of that page exists, it will be reused. Otherwise, a new copy of the page will be created and cached separately.

To get a better idea of how this process works, consider the following series of requests:

  1. You request a page without any query string parameter and receive page copy A.

  2. You request the page with the parameter ProductID=1. You receive page copy B.

  3. Another user requests the page with the parameter ProductID=2. That user receives copy C.

  4. Another user requests the page with ProductID=1. If the cached output B has not expired, it's sent to the user.

  5. The user then requests the page with no query string parameters. If copy A has not expired, it's sent from the cache.

You can try this on your own, although you might want to lengthen the amount of time that the cached page is retained to make it easier to test.


Output caching works well if the pages depend only on server-side data (for example, the data in a database) and the data in the query string. However, output caching doesn't work if the page output depends on user-specific information such as session data or cookies, because there's no way to vary caching based on these criteria. Output caching also won't work with dynamic pages that change their content in response to control events. In these situations, use fragment caching instead to cache a portion of the page, or use data caching to cache specific information.

3. Caching with Specific Query String Parameters

Setting VaryByParam to the wildcard asterisk (*) is unnecessarily vague. It's usually better to specifically identify an important query string variable by name. Here's an example:

<%@ OutputCache Duration="20" VaryByParam="ProductID" %>

In this case, ASP.NET will examine the query string, looking for the ProductID parameter. Requests with different ProductID parameters will be cached separately, but all other parameters will be ignored. This is particularly useful if the page may be passed additional query string information that it doesn't use. ASP.NET has no way to distinguish the "important" query string parameters without your help.

You can specify several parameters as long as you separate them with semicolons:

<%@ OutputCache Duration="20" VaryByParam="ProductID;CurrencyType" %>

In this case, ASP.NET will cache separate versions, provided the query string differs by ProductID or CurrencyType.

4. A Multiple Caching Example

The following example uses two web pages to demonstrate how multiple versions of a web page can be cached separately. The first page, QueryStringSender.aspx, isn't cached. It provides three buttons, as shown in Figure 2.

Figure 2. Three page options

A single event handler handles the Click event for all three buttons. The event handler navigates to the QueryStringRecipient.aspx page and adds a Version parameter to the query string to indicate which button was clicked—cmdNormal, cmdLarge, or cmdSmall.

Protected Sub cmdVersion_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles cmdNormal.Click, cmdLarge.Click, cmdSmall.Click

Response.Redirect("QueryStringRecipient.aspx" & _
"?Version=" & CType(sender, Control).ID)
End Sub

The QueryStringRecipient.aspx destination page displays the familiar date message. The page uses an OutputCache directive that looks for a single query string parameter (named Version):

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

In other words, this has three separately maintained HTML outputs: one where Version equals cmdSmall, one where Version equals cmdLarge, and one where Version equals cmdNormal.

Although it isn't necessary for this example, the Page.Load event handler in QueryRecipient.aspx tailors the page by changing the font size of the label accordingly. This makes it easy to distinguish the three versions of the page and verify that the caching is working as expected.

Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load

lblDate.Text = "The time is now:<br />" & DateTime.Now.ToString()

Select Case Request.QueryString("Version")
Case "cmdLarge"
lblDate.Font.Size = FontUnit.XLarge
Case "cmdNormal"
lblDate.Font.Size = FontUnit.Large
Case "cmdSmall"
lblDate.Font.Size = FontUnit.Small
End Select
End Sub

Figure 3 shows one of the cached outputs for this page.

Figure 3. One page with three cached outputs

5. Fragment Caching

In some cases, you may find that you can't cache an entire page, but you would still like to cache a portion that is expensive to create and doesn't vary frequently (like a list of categories in a product catalog). One way to implement this sort of scenario is to use data caching to store just the underlying information used for the page. You'll examine this technique in the next section. Another option is to use fragment caching.

To implement fragment caching, you need to create a user control for the portion of the page you want to cache. You can then add the OutputCache directive to the user control. The result is that the page will not be cached, but the user control will.

Fragment caching is conceptually the same as page caching. It has only one catch—if your page retrieves a cached version of a user control, it cannot interact with it in code. For example, if your user control provides properties, your web page code cannot modify or access these properties. When the cached version of the user control is used, a block of HTML is simply inserted into the page. The corresponding user control object is not available. To avoid potential problems in your code, don't attempt to interact with it in your code or check that it's not a null reference (Nothing) before you do.

6. Cache Profiles

One problem with output caching is that you need to embed the instruction into the page—either in the .aspx markup portion or in the code of the class. Although the first option (using the OutputCache directive) is relatively clean, it still produces management problems if you create dozens of cached pages. If you want to change the caching for all these pages (for example, moving the caching duration from 30 to 60 seconds), you need to modify every page. ASP.NET also needs to recompile these pages.

ASP.NET includes a feature called cache profiles that makes it easy to apply the same caching settings to a group of pages. With cache profiles, you define a group of caching settings in the web.config file, associate a name with these settings, and then apply these settings to multiple pages using the name. That way, you have the freedom to modify all the linked pages at once simply by changing the caching profile in the web.config file.

To define a cache profile, you use the <add> tag in the <outputCacheProfiles> section, as follows. You assign a name and a duration.

<add name="ProductItemCacheProfile" duration="60" />

You can now use this profile in a page through the CacheProfile attribute:

<%@ OutputCache CacheProfile="ProductItemCacheProfile" VaryByParam="None" %>

Interestingly, if you want to apply other caching details, such as the VaryByParam behavior, you can set it either as an attribute in the OutputCache directive or as an attribute of the <add> tag for the profile. Just make sure you start with a lowercase letter if you use the <add> tag, because the property names are camel case, as are all configuration settings, and case is important in XML.

PS4 game trailer XBox One game trailer
WiiU game trailer 3ds game trailer
Top 10 Video Game
-   Anno 2025 - E3 2015 Intro Trailer
-   Awesome GTA V Sniper Chopper Kill
-   Awesome GTA V Parachute Video
-   GTA V Explosive Ammo Rounds with Bikini
-   Funny GTA V Road Rage Clip
-   Cool GTA V Motorbike Jump
-   When a Mouse Jacks Your Truck in GTA V
-   Pig Riding a Motorbike in GTA V
-   Using an Uzi While Driving in GTA V
-   PlayStation 4 Ultimate Player 1TB Edition | Reveal Announcement
-   Dreamfall Chapters Book Three: Realms [PC] Zoe Trailer
-   Street Fighter V Trailer
-   Beyond Flesh and Blood | Beetham Folly Gameplay 1
-   Uncharted 4: A Thief's End | E3 2015 Gameplay Demo PS4
-   World of Warcraft | Patch 6.2 Survival Guide
Game of War | Kate Upton Commercial