Caching Portions of an ASP.NET Page

Sometimes it is impractical to cache an entire page; portions of the page may need to be dynamically created for each request. In these cases, it can be worthwhile for you to identify the objects or data associated with the page request that require significant server resources to construct. Once you identify these items, you can isolate them from the rest of the page by creating them in Web Forms user controls, and cache them for a period of time that you specify in order to save server resources. This is known as fragment caching.

This technique allows you to separate portions of a page that take valuable processor time to create, such as database queries, from other parts of the page. You can choose to allow parts of the page that require fewer server resources to be generated dynamically for each request.

Once you identify the portions of the page that you want to cache, and create the user controls that encapsulate each of those portions, you must determine the caching policies for the user controls. You can set these policies declaratively, using the @ OutputCache directive, or programmatically, using the PartialCachingAttribute class when creating your user control in a code-behind class.

For example, if you include the following directive at the top of a user control file, a version of the control is stored in the output cache for 120 seconds.

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

Similarly, if you develop your user control using the code-behind development method, a version of the control in the output cache is stored for 120 seconds when you include the following attribute in the metadata of your class declaration.

[PartialCaching(120)]
[Visual Basic]
<PartialCaching(120)>

Using either of these techniques, only the user control is cached when the page that contains the user control is requested.

Note   If a user control that is specified for output caching is declared and used within a page, the ASP.NET page parser instantiates one of two object types, depending on how the user control was created. If the user control was created declaratively, a StaticPartialCachingControl object is added; if the user control was created programmatically using the LoadControl method, then a PartialCachingControl object is added. Then, when the page is requested, the parser places the object into the logical position that a user control would occupy in the page's control hierarchy if it were not cached.

For more information on the attributes that you can set on page output, see the documentation on the @ OutputCache directive. For more information on how to develop user controls, see Web Forms User Controls.

Note   Since you can nest user controls in other server controls on a page, you can also nest user controls that have been placed in the output cache. This means that you can include an output-cache directive in a user control that is inside an output-cached page or in a user control that is part of another output-cached user control.

Common Mistakes When Using Fragment Caching

You can declare an ID attribute in a user control tag that you have specified for output caching in order to program against that instance of the user control. However, you must explicitly verify the existence of the user control in the output cache in order for the code to work properly.

For example, if you declaratively assign a user control an ID of MyUserControl, you can check for its existence with the following code in the containing .aspx file's code-declaration block.

void Page_Load() {
    if (MyUserControl != null)
       // Place code manipulating MyUserControl here.
}
[Visual Basic]
Sub Page_Load()
    If MyUserControl <> Null Then
       ' Place code manipulating MyUserControl here.
    End If  
End Sub

If you write code to manipulate a user control that contains an @ OutputCache directive, an error will occur. A user control that is output cached is dynamically generated only for the first request; any subsequent requests are satisfied from the output cache until the specified time expires. Once you have determined that the user control has been instantiated, you can programmatically manipulate the user control from the containing page. You can include this logic in one of the page lifecycle events associated with the user control, such as in the Page_Load event or the Page_PreRender event.

You should also be aware of what happens when a user control with output caching set exists in a Web Forms page that also has output caching set. If the page output cache duration is longer than the user control output cache duration, the page output cache duration is effective for the entire page, including the user control. For example, if page output caching is set to 100 seconds and the user control output caching is set to 50 seconds, the entire page is stored in the output cache for 100 seconds, regardless of the shorter setting for the user control. The following example demonstrates this.

page01.aspx

<%@ Page language="C#" %>
<%@ Register tagprefix="myControl" tagname="Time" src="uc01.ascx" %>
<%@ OutputCache duration="100" varybyparam="none" %>

<myControl:Time runat="server" /><br> <br> <br>

This page was most recently generated at:<p>

 <% DateTime t = DateTime.Now; 
    Response.Write(t); %>
[Visual Basic]
<%@ Register tagprefix="myControl" tagname="Time" src="uc01.ascx" %>
<%@ OutputCache duration="100" varybyparam="none" %>

<myControl:Time runat="server" /><br> <br> <br>

This page was most recently generated at:<p>
 <% Dim t As DateTime = DateTime.Now
Response.Write(t) %>

uc01.ascx

<% @Control language="C#" %>
<% @OutputCache duration="100" varybyparam="none" %>

This user control was most recently generated at:<p>

<% DateTime t = DateTime.Now; 
    Response.Write(t); %>
[Visual Basic]
<% @OutputCache duration="100" varybyparam="none" %>

This user control was most recently generated at:<p>
<% Dim t As DateTime = DateTime.Now
Response.Write(t) %>

However, if the page output cache duration is less than that of a user control output cache duration, the cached user control will be used until its duration has expired even when the rest of the page is regenerated for a request. For example, if page output caching is set to 50 seconds, while user control output caching is set to 100 seconds, the user control expires once for every two times the rest of the page expires. The following simple example demonstrates this.

page02.aspx

<%@ Page language="C#" %>
<%@ Register tagprefix="myControl" tagname="Time" src="uc02.ascx" %>

<%@ OutputCache duration="50" varybyparam="none" %>

<myControl:Time runat="server" /><br> <br> <br>

This page was most recently generated at:<p>

 <% DateTime t = DateTime.Now; 
    Response.Write(t); %>
[Visual Basic]
<%@ Register tagprefix="myControl" tagname="Time" src="uc02.ascx" %>
<%@ OutputCache duration="50" varybyparam="none" %>

<myControl:Time runat="server" /><br> <br> <br>

This page was most recently generated at:<p>
 <% Dim t As DateTime = DateTime.Now
Response.Write(t) %>

uc02.ascx

<% @Control language="C#" %>
<% @OutputCache duration="100" varybyparam="none" %>

This user control was most recently generated at:<p>

<% DateTime t = DateTime.Now; 
    Response.Write(t); %>
[Visual Basic]
<% @OutputCache duration="100" varybyparam="none" %>

This user control was most recently generated at:<p>
<% Dim t As DateTime = DateTime.Now
Response.Write(t) %>

See Also

Web Forms User Controls | Caching ASP.NET Pages | @ OutputCache | ASP.NET Caching Features | PartialCachingControl Class | Caching Multiple Versions of User Control Output | PartialCachingAttribute Class | UserControl Class | ASP.NET Optimization