A ASP.NET Caching Features
One of the most important factors in building high-performance, scalable Web applications is the ability to store items, whether data objects, pages, or parts of a page, in memory the initial time they are requested. You can store these items on the Web server or other software in the request stream, such as the proxy server or browser. This allows you to avoid recreating information that satisfied a previous request, particularly information that demands significant processor time or other resources. Known as caching, it allows you to use a number of techniques to store page output or application data across HTTP requests and reuse it. Thus, the server does not have to recreate information, saving time and resources.
ASP.NET provides two types of caching that you can use to create high-performance Web applications. The first is called output caching, which allows you to store dynamic page and user control responses on any HTTP 1.1 cache-capable device in the output stream, from the originating server to the requesting browser. On subsequent requests, the page or user control code is not executed; the cached output is used to satisfy the request. The second type of caching is traditional application data caching, which you can use to programmatically store arbitrary objects, such as data sets, to server memory so that your application can save the time and resources it takes to recreate them.
Caching ASP.NET Pages
ASP.NET allows you to cache the entire response content for dynamic pages on HTTP 1.1 capable mechanisms, including browsers, proxy servers, and the Web server where your application resides. This provides a powerful way for you to increase the performance of your Web applications. Called output caching, it allows subsequent requests for a particular page to be satisfied from the cache so the code that initially creates the page does not have to be run upon subsequent requests. Using this technique to cache your site's most frequently accessed pages can increase your Web server's throughput, commonly measured in requests per second, substantially.
You have your choice of a high-level declarative API or a low-level programmatic API when manipulating the output cache for a page. You can use the former by including the @ OutputCache directive in the .aspx file for the page. The @ OutputCache directive can meet nearly all the common needs you may have when you want to cache a page's output. The following directive, when included in an .aspx file, sets an expiration of 60 seconds for the cached output of a dynamically generated page.
<%@ OutputCache Duration="60" VaryByParam="None" %>
CAUTION When you use the @ OutputCache directive, the Duration and VaryByParam attributes are required. If you do not include them, a parser error occurs when the page is first requested. If you do not want to use the functionality that the VaryByParam attribute provides, you must set its value to None. For more information about using the VaryByParam attribute, see Caching Multiple Versions of a Page .
ASP.NET also includes a set of APIs that control output-cache expirations and policies for a page programmatically through the HttpCachePolicy class. This class, its methods, and its properties are available through the HttpResponse.Cache property. In turn, you can access this property from the Page object through the Page.Response property.
For example, the following code, when included in a page's code-declaration block or its code-behind class, sets an expiration of 60 seconds using the HttpCachePolicy.SetExpires method for the dynamically generated page.
[C#]
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
[Visual Basic]
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60))
Once you have enabled output caching, the initial HTTP GET request for the page places its dynamic content in the output cache for the amount of time you specify. The output cache satisfies subsequent GET, HEAD, or POST requests for that page until the amount of time you specify expires.
You can enable or disable page output caching for cache-capable devices in the request stream either declaratively or programmatically as well. In the @ OutputCache directive for a page you can use the Location attribute to specify whether the page's output can be cached on proxy servers, browser clients, the originating Web server, or all or none of these. You can do the same programmatically using the HttpCachePolicy.SetCacheability method to specify the appropriate HttpCacheability enumeration value for your page. For more information, see Setting the Cacheability of a Page.
Responses generated by GET requests with query string parameters or form POST requests with parameters can also be cached, but caching for the passed parameters must be explicitly enabled using the @ OutputCache directive's VaryByParam attribute. For more information, see Caching Multiple Versions of a Page .
Remember that any manipulations that you want to make programmatically to the output cache must be made in the code-declaration block of an .aspx file, or in a code-behind class associated with the .aspx file.
Setting Expirations for Page Caching
To add a page to the output cache, you must establish an expiration policy for that page. You can do this declaratively with the @ OutputCache directive or programmatically using the HttpCachePolicy.SetExpires method. The @ OutputCache directive sets the Cache-Control header to Public by default.
If you set expirations for a page programmatically, you must set the Cache-Control header for the cached page as well. Use the HttpCachePolicy.SetCacheability method to set the HttpCacheability enumeration to Public.
To set output-cache expirations for a page declaratively
· Include an @ OutputCache directive in the page (.aspx file) whose response you want to store in the output cache. The directive must include a Duration attribute, with a positive numeric value, and a VaryByParam attribute. The following @ OutputCache directive sets the page's expiration to 60 seconds.
<%@ OutputCache Duration="60" VaryByParam="None" %>
Note You must include a VaryByParam attribute when using the @ OutputCache directive or a parser error will occur. If you do not want to use the functionality offered by the VaryByParam attribute, set its value to None. For more information about using the VaryByParam attribute, see Caching Multiple Versions of a Page.
To set output-cache expirations for a page programmatically
· In the page's code-declaration block, or in the code-behind class for the page, include code that sets the expiration policy for the page by using Response.Cache syntax. The following example sets expirations for the page as the @ OutputCache directive does in the previous procedure.
· [C#]
· Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
· Response.Cache.SetCacheability(HttpCacheability.Public);
· Response.Cache.SetValidUntilExpires(true);
· [Visual Basic]
· Response.Cache.SetExpires(DateTime.Now.AddSeconds(60))
· Response.Cache.SetCacheability(HttpCacheability.Public)
Response.Cache.SetValidUntilExpires(True)
Once the duration for the cached page expires, the subsequent request for the page causes a dynamically generated response. This response page is cached again for the specified duration.
Setting the Cacheability of a Page
The cacheability of a page or user control defines which HTTP 1.1 Internet devices a document can be cached on. These devices include the client making the request, the Web server responding to the request, and any cache-capable devices, such as proxy servers, that are in the request or response stream. When a Web server sends a response, it passes a Cache-Control HTTP header that, among other things, defines the devices on which the document can be cached. ASP.NET defines these values in the HttpCacheability enumeration. This enumeration has six values, four that map directly to Cache-Control HTTP header settings and two special values called HttpCacheability.ServerAndPrivate and HttpCacheability.ServerAndNoCache. ServerAndPrivate allows a response to be cached only on the origin server and the requesting client. ServerAndNoCache allows a response to be cached only on the origin server.
Depending on the needs of your application, you may choose to define which devices can and cannot cache specific pages. For example, you would want the cacheability settings for a user logon page to be different from those for a page that displays a selection of products from a catalog. In the case of the logon page, for security reasons you would want to cache the page on only the server, while the catalog page could probably be cached on any cache-capable device.
You can set the cacheability of a page's output declaratively by including a Location attribute in the @ OutputCache directive and specifying one of the OutputCacheLocation enumeration values.
You can set the cacheability of a page's output programmatically by using the HttpCachePolicy.SetCacheability method to specify an HttpCacheability value for the page. The method is accessible through the HttpResponse.Cache property, which is accessible using Response.Cache syntax in the page's code-behind class or code-declaration block.
Note If you use the @ OutputCache directive to set your page's cacheability, you must declare the Duration and VaryByParam attributes along with the Location attribute. The Duration attribute must be set to a value larger than zero. You can set the VaryByParam attribute to None if you do not want to use the functionality it provides. For more information, see Setting Expirations for Page Caching and Caching Multiple Versions of a Page.
In contrast, if you use the HttpCachePolicy class to set cacheability, you do not need to set expirations if you have established a validation policy.
To set a page's cacheability declaratively
1. Include an @ OutputCache directive in the .aspx file and define the required Duration and VaryByParam attributes.
2. Include a Location attribute in the @ OutputCache directive and define its value as one of the supported values. These include Any, Client, Downstream, Server, or None.
Note The default is Any. If you do not define a Location attribute, the page output can be cached on all cache-capable network applications that are involved in the response. These include the requesting client, the origin server, and any proxy servers through which the response passes.
To set a page's cacheability programmatically
· In the page's code-declaration block or code-behind class file, use Response.Cache syntax to access the HttpCachePolicy.SetCacheability method. The following code sets the Cache-Control HTTP header to Public.
· [C#]
· Response.Cache.SetCacheability(HttpCacheability.Public);
· [Visual Basic]
Response.Cache.SetCacheability(HttpCacheability.Public)
Note If you set cacheability to HttpCacheability.NoCache or HttpCacheability.ServerAndNoCache, the requesting client will not cache pages in its History folder. For example, any time a user clicks a back or forward button, a new version of the response will be requested. You can override this behavior by setting the HttpCachePolicy.SetAllowResponseInBrowserHistory method to true.
[C#]
Response.Cache.SetAllowResponseInBrowserHistory(true);
[Visual Basic]
Response.Cache.SetAllowResponseInBrowserHistory(true)
If you set cacheability to any value other than NoCache or ServerAndNoCache , ASP.NET ignores the value set by the SetAllowResponseInBrowserHistory method.
Checking the Validity of a Cached Page
When the output cache has an existing entry that it would like to use as a response to a client request, it must first check with the origin server (or an intermediate cache, such as a proxy server, with a fresh response) to determine if the cached entry is still usable. This process is called validating the cache entry. To avoid wasting resources either from regenerating and retransmitting the page if the cached entry is valid or from an extra round trip if the cached entry is invalid, ASP.NET provides a mechanism for you to validate a cached page programmatically.
Note For more information about cache validity and its requirements, see the HTTP 1.1 specification at www.w3.org.
To determine the validity of a cached page, you must define an event handler with the same signature as the HttpCacheValidateHandler delegate. This handler should perform a check to determine if the page stored in the cache remains valid, then assign one of the HttpValidationStatus enumeration values to the possible returns from the check. This enumeration has three values:
· Invalid, which indicates that the cached page is invalid, the page is evicted from the cache, and the request is handled as a cache miss.
· IgnoreThisRequest, which causes the request to be treated as a cache miss and the page is executed, but the cached page is not invalidated.
· Valid, which indicates that the cached page remains valid.
In one of the page lifecycle events, the HttpCachePolicy.AddValidationCallback method takes your event handler as a parameter. Before the response is served from the Web server cache, all registered handlers are queried to ensure resource validity. If any handler sets a flag that indicates the resource is invalid, the entry is marked invalid and evicted from the cache. The request is then handled as if it were a cache miss.
To check the validity of a cached page
1. Define an event handler of type HttpCacheValidateHandler that checks the validity of the cached page response.
The following example creates an event handler, Validate, that checks the Text property value of a myText TextBox Web server control. Depending upon the value entered in the text box, Validate returns the appropriate HttpValidationStatus enumeration value.
[C#]
public void Validate(HttpContext context, Object data, ref HttpValidationStatus status)
{
if (myText.Text == "false") {
status = HttpValidationStatus.Invalid;
} else if (myText.Text == "ignore") {
status = HttpValidationStatus.IgnoreThisRequest;
} else {
status = HttpValidationStatus.Valid;
}
}
[Visual Basic]
Public Sub Validate(context As HttpContext, data As [Object], ByRef status As HttpValidationStatus)
If myText.Text = "false" Then
status = HttpValidationStatus.Invalid
Else
If myText.Text = "ignore" Then
status = HttpValidationStatus.IgnoreThisRequest
Else
status = HttpValidationStatus.Valid
End If
End If
End Sub 'Validate
2. From one of the page lifecycle events, call the HttpCachePolicy.AddValidationCallback method, passing the event handler you defined in the first parameter argument in step 1.
In the following code example, the Page_Load method calls AddValidationCallback with the Validate event handler that was passed in the first parameter argument in step 1.
[C#]
public void Page_Load(){
Response.Cache.AddValidationCallback(new HttpCacheValidateHandler(Validate), null);
}
[Visual Basic]
Public Sub Page_Load()
Response.Cache.AddValidationCallback(New HttpCacheValidateHandler(Validate), Nothing)
End Sub 'Page_Load
The following example uses the event handler defined in step one with the code in step 2 and writes a time stamp to the page.
Note This example is intended to easily show how a page in the cache can be invalidated. Most scenarios you create should validate the page against some state on the server, which is associated with the page that changes.
[C#]
<%@ OutputCache Duration=100 varybyparam="none" %>
<Script Language="C#" runat="server">
public void Page_Load(){
if(!IsPostback) {
myText.Text = "Enter validation request." ;
}
Response.Cache.AddValidationCallback(new HttpCacheValidateHandler(Validate), null);
stamp.InnerHtml = DateTime.Now.ToString("r");
}
public void Button1_Click(){
Validate();
}
public void Validate(HttpContext context, Object data, ref HttpValidationStatus status) {
if (myText.Text == "false") {
status = HttpValidationStatus.Invalid;
} else if (myText.Text == "ignore") {
status = HttpValidationStatus.IgnoreThisRequest;
} else {
status = HttpValidationStatus.Valid;
}
}
</Script>
<form runat="server" >
<asp:textbox id="myText" runat="server" />
<br>
<asp:button id="mybutton" click="Button1_Click" text="Click here to validate page." runat="server" />
</form>
<br>
<b>In the text box, enter false to invalidate the cached page, ignore to ignore the current request, or any other string to leave the output cached page valid. </b>
<br>
<br>
<Font size=6><B id=stamp runat=server /></Font>
[Visual Basic]
<%@ OutputCache Duration=100 varybyparam="none" %>
<Script Language="VB" runat="server">
Public Sub Page_Load()
If Not IsPostback Then
myText.Text = "Enter validation request."
End If
Response.Cache.AddValidationCallback(New HttpCacheValidateHandler(Validate), Nothing)
stamp.InnerHtml = DateTime.Now.ToString("r")
End Sub 'Page_Load
Public Sub Button1_Click()
Validate()
End Sub 'Button1_Click
Public Sub Validate(context As HttpContext, data As [Object], ByRef status As HttpValidationStatus)
If myText.Text = "false" Then
status = HttpValidationStatus.Invalid
Else
If myText.Text = "ignore" Then
status = HttpValidationStatus.IgnoreThisRequest
Else
status = HttpValidationStatus.Valid
End If
End If
End Sub 'Validate
</Script>
<form runat="server" >
<asp:textbox id="myText" runat="server" />
<br>
<asp:button id="mybutton" click="Button1_Click" text="Click here to validate page." runat="server" />
</form>
<br>
<b>In the text box, enter false to invalidate the cached page, ignore to ignore the current request, or any other string to leave the output cached page valid. </b>
<br>
<br>
<Font size=6><B id=stamp runat=server /></Font>
Caching Page Output with Cache Key Dependencies
When you add pages to the output cache, the page will be removed when the amount of time you specify in the expiration policy has passed. There are times when you want a page, or versions of a page, to be removed from the output cache before it has expired. For example, if your page displays volatile data, such as a stock price or a temperature, the page will display incorrect information if the data is updated before the page expires.
To address this issue, ASP.NET provides the HttpResponse.AddCacheItemDependency and HttpResponse.AddCacheItemDependencies methods, which allow you to cache page output that is dependent upon an item in the Cache object (associated with the application that the page belongs to).
Note You can explicitly remove any page from the output cache by calling the HttpResponse.RemoveOutputCacheItem method. You can do this from the global.asax file, a custom ASP.NET server control you have created, or from a page, depending upon the needs of your application.
The AddCacheItemDependency method allows you to create a relationship between the page and a single item in the Cache, while the AddCacheItemDependencies method allows you to create relationship between the page and an array of Cache items. When any of the items upon which the page is dependent change or are removed from the application Cache, the page output is invalidated and removed from the output cache.
Note You cannot use these methods from a Web Forms user control.
To make cached page output dependent upon a Cache item
1. Specify the settings for caching page output either declaratively or programmatically. For more information, see Setting Expirations for Page Caching, Setting the Cacheability of a Page, and Caching Multiple Versions of a Page.
2. In the code-declaration block or the code-behind file for the page, add an item to your Web application's Cache object using the Cache.Item property, the Cache.Add method, or the Cache.Insert method.
3. In the code-declaration block or the code-behind file for the page, use Response object syntax to call the AddCacheItemDependency or AddCacheItemDependencies method, specifying the cached item or items upon which the page is dependent.
CAUTION To use these methods, the argument passed to it must be the cache key specified for the cached item specified in the Cache.Item property, the Cache.Add method, or the Cache.Insert method.
The following example assumes that an application contains a temperature component. The component uses the Cache.Insert method to place a temperature into the application Cache.
[C#]
Cache.Insert("Temperature.CurrentTemperature", currentTemperature);
[Visual Basic]
Cache.Insert("Temperature.CurrentTemperature", currentTemperature)
The following page code, found in a code-declaration block or code-behind file, gets the current temperature stored in the Cache, converts it to a string, and then displays it. It then makes its output cache version dependent upon the Temperature.CurrentTemperature key. From this point forward, when the temperature component updates the temperature, the page version is flushed from the output cache. The page will be placed in the output cache again when it is subsequently requested.
[C#]
int temperature = (int) Cache.Get("Temperature.CurrentTemperature");
LabelTemperature.Text = temperature.ToString();
Response.AddCacheItemDependency("Temperature.CurrentTemperature");
[Visual Basic]
Dim temperature as Integer
temperature = Cache.Get("Temperature.CurrentTemperature")
LabelTemperature.Text = temperature.ToString()
Response.AddCacheItemDependency("Temperature.CurrentTemperature")
Caching Page Output with File Dependencies
When you add a page to the output cache, the page will be removed when the amount of time you specify in the expiration policy has passed. There are times when you want a page, or versions of a page, to be removed from the output cache before it has expired. To do this, you can use the HttpResponse.AddFileDependency method to make the cached page dependent on a single file, or the HttpResponse.AddFileDependencies method to make the cached page dependent upon a group of files represented by an ArrayList object.
For example, if you use XML files as data stores for your page, you create an ArrayList that contains the names of all the files that the page uses. You can then call AddFileDependencies to make the page dependent upon that ArrayList. When any of the XML files change, the page is removed from the output cache and a new page is generated upon the next request.
Note You cannot use these methods from a Web Forms user control.
Note You can explicitly remove any page from the output cache by calling the HttpResponse.RemoveOutputCacheItem method. You can do this from the global.asax file, from a custom ASP.NET server control you have created, or from a page, depending on the needs of your application.
To make cached page output dependent upon a file
1. Specify the settings for caching page output either declaratively or programmatically. For more information, see Setting Expirations for Page Caching, Setting the Cacheability of a Page, and Caching Multiple Versions of a Page.
2. In the code-declaration block or the code-behind file for the page, create a String object. This will be passed as the parameter argument in the AddFileDependency method call.
3. [C#]
4. static string filePath;
5. [Visual Basic]
Shared filePath As [String]
6. In the Page_Load method, or another ASP.NET page lifecycle method, set the string you created in step 2 to the absolute path of the dependent file with the HttpServerUtility.MapPath method.
7. [C#]
8. filePath = Server.MapPath("authors.xml");
9. [Visual Basic]
filePath = Server.MapPath("authors.xml")
10. In the same page lifecycle method you used in step 3, access Response property syntax to call the AddFileDependency method, passing the String object you created in Step 2 in the filename parameter.
11. [C#]
12. Response.AddFileDependency(filePath);
13. [Visual Basic]
Response.AddFileDependency(filePath)
To make cached page output dependent upon a group of files
1. Specify the settings for caching page output either declaratively or programmatically. For more information, see Setting Expirations for Page Caching, Setting the Cacheability of a Page, and Caching Multiple Versions of a Page.
2. In the code-declaration block or the code-behind file for the page, create an ArrayList object that contains the names of the dependent files.
3. [C#]
4. ArrayList depAL = new ArrayList();
5. depAL.Add(Server.MapPath("authors.xml"));
6. depAL.Add(Server.MapPath("products.xml"));
7. [Visual Basic]
8. Dim depAL As New ArrayList()
9. depAL.Add(Server.MapPath("authors.xml"))
depAL.Add(Server.MapPath("products.xml"))
10. In one of the page lifecycle methods, such as Page_Load, use Response object syntax to call the AddFileDependencies method, passing the ArrayList object you created in Step 2 in the filenames parameter.
11. [C#]
12. Response.AddFileDependencies(depAL);
13. [Visual Basic]
Response.AddFileDependencies(depAL)
The following example uses the AddFileDependency method to make the cached page dependent upon an XML file, authors.xml . Once the page has been requested, it is stored in the output cache for 100 seconds. However, if the XML file changes before that amount of time elapses, the page output is removed from the cache. The next time the page is requested, a new version will be stored in the output cache. To test this, manually add another entry to the XML file after you request the page, and then refresh the page from your browser.
[C#]
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>
<%@ OutputCache duration="100" varybyparam="false" %>
<html>
<script language="C#" runat="server">
static String filePath;
void Page_Load(Object Src, EventArgs E ) {
filePath = Server.MapPath("Authors.xml");
Response.AddFileDependency(filePath);
LoadData();
TimeMsg.Text = DateTime.Now.ToString("G");
}
void LoadData() {
// Read the data from the XML source.
DataSet ds = new DataSet();
FileStream fs = new FileStream(Server.MapPath("authors.xml"), FileMode.Open,FileAccess.Read);
StreamReader reader = new StreamReader(fs);
ds.ReadXml(reader);
fs.Close();
// Create a DataView object to bind to
// the DataGrid on the page.
DataView Source = new DataView(ds.Tables[0]);
// Bind the Source to the DataGrid on the page.
MyDataGrid.DataSource = Source;
MyDataGrid.DataBind();
}
</script>
<body>
<form runat="server">
<h3><font face="Verdana">File Dependencies</font></h3>
<ASP:DataGrid id="MyDataGrid" runat="server"
Width="300"
BackColor="#ccccff"
BorderColor="black"
ShowFooter="false"
CellPadding=3
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
/>
<p>
<i>Last generated on:</i> <asp:label id="TimeMsg" runat="server" />
</form>
</body>
</html>
[Visual Basic]
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>
<%@ OutputCache duration="100" varybyparam="false" %>
<html>
<script language="VB" runat="server">
' Create a string to pass to AddFileDependency.
Shared filePath As [String]
Sub Page_Load(Src As [Object], E As EventArgs)
' Assign the string the absolute path to the
' dependent file, then pass it to AddFileDependency.
filePath = Server.MapPath("Authors.xml")
Response.AddFileDependency(filePath)
' Call this function to display XML data in the page.
LoadData()
TimeMsg.Text = DateTime.Now.ToString("G")
End Sub 'Page_Load
Sub LoadData()
' Read the data from the XML source.
Dim ds As New DataSet()
Dim fs As New FileStream(Server.MapPath("authors.xml"), FileMode.Open, FileAccess.Read)
Dim reader As New StreamReader(fs)
ds.ReadXml(reader)
fs.Close()
' Create a DataView object to bind to
' the DataGrid on the page.
Dim [Source] As New DataView(ds.Tables(0))
' Bind the Source to the DataGrid on the page.
MyDataGrid.DataSource = [Source]
MyDataGrid.DataBind()
End Sub 'LoadData
</script>
<body>
<form runat="server">
<h3><font face="Verdana">File Dependencies</font></h3>
<ASP:DataGrid id="MyDataGrid" runat="server"
Width="300"
BackColor="#ccccff"
BorderColor="black"
ShowFooter="false"
CellPadding=3
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
/>
<p>
<i>Last generated on:</i> <asp:label id="TimeMsg" runat="server" />
</form>
</body>
</html>
The contents of the authors.xml file are as follows.
<NewDataSet>
<Table>
<au_id>172-32-1176</au_id>
<au_lname>White</au_lname>
<au_fname>Johnson</au_fname>
</Table>
<Table>
<au_id>213-46-8915</au_id>
<au_lname>Green</au_lname>
<au_fname>Marjorie</au_fname>
</Table>
</NewDataSet>
Caching Multiple Versions of a Page
Depending on its complexity, when an ASP.NET page is requested, there are a number of possible responses that it can generate. For example, if you design your page with an HTML form that allows users to look up retailer locations near their home, and includes city and zip code input boxes, the page response can be different for each user. You can choose to cache a version of the page output for each city, each zip code, or both.
ASP.NET allows you to cache multiple versions of a page response. You can vary the output cache by GET query string or form POST parameters that are passed with a request, by the HTTP headers passed with a request, or by the major version of the browser that is making the request. You can also define a custom string in the page and implement how you want it to affect the response caching in your application's Global.asax file.
ASP.NET allows you to cache multiple versions of a page response declaratively by using attributes on the @ OutputCache directive and programmatically by using the properties and methods of the HttpCachePolicy class.
Specifically, the @ OutputCache directive includes three attributes that allow you to cache multiple versions of page output:
· The required VaryByParam attribute allows you to vary the cached output depending on GET query string or form POST parameters.
· The VaryByHeader attribute allows you to vary the cached output depending on the HTTP header associated with the request.
· The VaryByCustom attribute allows you to vary the cached output by browser type or by a custom string that you define.
Note While you must include the VaryByParam attribute in any @ OutputCache directive, you can set its value to None if you do not want to use the functionality it provides.
The HttpCachePolicy class provides two properties and a method that allow you to do the same things that the aforementioned attributes do. The Boolean VaryByParams and VaryByHeaders properties allow you to specify the parameter and header names, respectively, that you want to vary the cache by. The SetVaryByCustom method allows you to define custom strings by which to vary the output cache.
For procedures and in-depth discussions on these techniques, see Caching Versions of a Page Based on Parameters, Caching Versions of a Page Based on HTTP Headers, and Caching Versions of a Page Based on Custom Strings.
Caching Versions of a Page, Based on Parameters
If you use GET and POST HTTP methods to gather information from users, you know that they can generate different responses depending on user input. GET requests with query strings and POST requests are associated with HTML forms, with which you can gather information from users. You can cache multiple versions of page responses, based on these parameters. To do this, you can use the @ OutputCache directive's VaryByParam attribute, or the HttpCachePolicy.VaryByParams property.
To cache multiple versions of page output declaratively, based on query string or form POST parameters
1. Include an @ OutputCache directive in the .aspx file that you want to cache. Be sure to set the required Duration attribute to a value greater than zero.
2. Use the VaryByParam attribute to set the query string or form POST parameter that you want to vary the page by. By including the following example at the top of an .aspx file, different versions of page output will be cached for each request that arrives with a different City parameter value.
<%@ OutputCache duration="60" varybyparam="City" %>
Note If you want to vary the output cache by multiple parameters, define them in the VaryByParam attribute by using a semicolon-delimited list. If you want vary the cache by all the parameter values, set the attribute to an asterisk (*).
To cache multiple versions of page output programmatically, based on query string or form POST parameters
1. In the page's code-declaration block or code-behind class, use Response.Cache syntax to set the expiration and visibility policies for the cached page content. You can accomplish this using the HttpCachePolicy.SetExpires and HttpCachePolicy.SetCacheability methods, respectively.
2. In the same code, specify the parameter name as the argument for the VaryByParams property and set the property to true. The following code caches multiple versions of a page when requests arrive at the server with different City parameter values.
3. [C#]
4. Response.Cache.VaryByParams["City"] = true;
5. [Visual Basic]
Response.Cache.VaryByParams("City") = true
Note If you want to vary the output cache by multiple parameters, include them in a semicolon-delimited list in the VaryByParams argument. If you want vary the cache by all the parameter values, set the attribute to an asterisk (*).
The following example demonstrates varying the page output by City and ZipCode parameters.
[C#]
Response.Cache.VaryByParams["City;ZipCode"] = true;
[Visual Basic]
Response.Cache.VaryByParams("City;ZipCode") = true
The following discussion details how versions of a page are cached, depending upon incoming requests with different values that are passed in form POST or query string parameters.
Your application contains an .aspx file, Mycache.aspx, and you specify that different versions of the page should be cached, based on a city parameter. Four requests arrive with query strings attached: two with count parameters and four with city parameters.
http://www.microsoft.com/caching/mycache.aspx?count=10&city=dallas
http://www.microsoft.com/caching/mycache.aspx?count=10&city=newyork
http://www.microsoft.com/caching/mycache.aspx?city=dallas
http://www.microsoft.com/caching/mycache.aspx?city=seattle
Since you instruct the output cache to vary by only the city parameter, three versions of the page's output are cached, one for dallas, one for newyork, and one for seattle . The first request, containing the dallas parameter value, causes a version of the page output to be cached, while the third request, also with the dallas parameter value, obtains the version of the page from the output cache. For the length of time that these versions remain in the cache, requests that contain city parameters with the value of dallas, new york, or seattle are satisfied from the output cache.
If you vary the output cache by both the city and count parameters, four versions of the page output are cached. This is the case because the first entry contains a count query string parameter, while the third entry does not. If you vary the cache by all possible parameters, an output-cache entry is created for each request with unique parameter values. In the current example, this also causes four versions of the page to be cached.
Note GET query string or form POST parameters with identical pairs of keys and values, regardless of the order that those parameters are passed, are satisfied by the cached version of the page for as long as it has not expired. Since GET query string and form POST parameters are case-sensitive, if the parameter value is cased differently ASP.NET will treat the parameter as different from the original cached item and enter another version of the page in the output cache.
Caching Versions of a Page, Based on HTTP Headers
The @ OutputCache directive's VaryByHeader attribute and the HttpCachePolicy.VaryByHeaders property allow you to cache multiple versions of a page, dependent on the value of an HTTP header that you specify. You can specify a single header, multiple headers, or all headers passed to your application, when the page is requested. Depending upon the header or combination of headers you choose, multiple versions of the page's output is cached.
To cache versions of a page declaratively, based on HTTP header values
1. Include an @ OutputCache directive with the required Duration and VaryByParam attributes. The Duration attribute must be set to any integer greater than zero. If you do not want to use the functionality provided by the VaryByParam attribute, set its value to None.
2. Include the VaryByHeader attribute in the body of the @ OutputCache directive, with its value set to the name of the HTTP header that you want to vary the cache content by. The following example sets versions of a page to be cached, based on the value passed with the Accept-Language HTTP header.
<%@ OutputCache Duration="60" VaryByParam="None" VaryByHeader="Accept-Language" %>
Note If you want to vary the cached content by multiple headers, include a semicolon delimited list of header names. If you want to vary the cached content by all header values, set the VaryByHeader attribute equal to an asterisk (*).
To cache versions of a page programmatically, based on an HTTP header value
1. In the page's code-declaration block or code-behind class, use Response.Cache syntax to set the expiration and visibility policies for the cached page content. You accomplish this using the HttpCachePolicy.SetExpires and HttpCachePolicy.SetCacheability methods, respectively.
2. In the same code, specify the header name as the argument for the VaryByHeaders property, and set the property to true. The following code caches multiple versions of a page when requests arrive at the server that have different values assigned to the Accept-Language HTTP header.
3. [C#]
4. Response.Cache.VaryByHeaders["Accept-Language"] = true;
5. [Visual Basic]
Response.Cache.VaryByHeaders("Accept-Language") = true
Note If you want to vary the cache by multiple header values, set the VaryByHeaders property argument to a semicolon delimited list of valid HTTP header names. If you want to vary the pages in the cache by all HTTP header names, use the VaryByUnspecifiedParameters method.
The following discussion assumes that a page's output is cached by using the code from one of the procedures in this topic.
Four requests arrive for the page with the following Accept-Language headers.
de-lu
en-us
fr
en-us
Since the second and fourth requests have the same Accept-Language HTTP header values, only the response generated for the first request is cached. The other two Accept-Language values generate page output versions that are also cached. A total of three documents are rendered and cached for these four requests. Any further requests for the page with the same Accept-Language values are satisfied from the output cache until the cached pages expire. This example demonstrates how to cache the page output of globalized content, depending upon the locale settings for the requesting browser.
Caching Versions of a Page, Based on Requesting Browser
You can use the @ OutputCache directive's VaryByCustom attribute or the HttpCachePolicy.SetVaryByCustom method to vary the versions of page output by the major version of the browser that requests the page. This major version and browser type information is passed through the HttpBrowserCapabilities.MajorVersion property associated with the current request. You could access this information through the Request object associated with the page, but it is simpler to use the built-in functionality offered by ASP.NET.
To cache multiple versions of a page output declaratively based on browser type
1. In the .aspx file, include an @ OutputCache directive with the required Duration and VaryByParam attributes. The Duration attribute must be set to any integer greater than zero. If you do not want to use the functionality provided by the VaryByParam attribute, you must set its value to None.
2. In the body of the @ OutputCache directive, include the VaryByCustom attribute and set it to browser.
<%@ OutputCache Duration="10" VaryByParam="None" VaryByCustom="browser" %>
To cache multiple versions of a page response programmatically, based on custom strings
1. In the page's code-declaration block or code-behind class, use Response.Cache syntax to set the expiration and visibility policies for the cached page content. You accomplish this by using the HttpCachePolicy.SetExpires and HttpCachePolicy.SetCacheability methods, respectively. For more information, see Setting Expirations for Page Caching and Setting the Cacheability of a Page.
2. In the same code, specify browser in the custom parameter of the SetVaryByCustom method.
3. [C#]
4. Response.Cache.SetVaryByCustom("browser");
5. [Visual Basic]
Response.Cache.SetVaryByCustom("browser")
Regardless of which of these techniques you use, when you specify browser, ASP.NET automatically caches versions of the page output based on the browser name and major version information passed in the Request.Browser.Type property, with the current request. This information is available through the HttpContext class associated with the request.
For example, when an Internet Explorer 5 browser requests a page, the version of the page is cached for the string value "IE5" that is passed in the Type property for the request. When a Netscape Navigator browser, another version of Internet Explorer, or any other browser requests the page, another version of the page is added to the output cache.
Caching Versions of a Page, Based on Custom Strings
In addition to varying the output cache by browser type, the @ OutputCache directive's VaryByCustom attribute and the HttpCachePolicy.SetVaryByCustom method allow you to cache multiple versions of page output by a custom string that you define.
When you choose to extend the functionality of the output cache, using either of these techniques, you must override the HttpApplication.GetVaryByCustomString method in your application's Global.asax file. The code that you write in your override statement defines how your application caches any page output that is varied by the custom string or strings that you specify.
To cache multiple versions of page output declaratively, based on custom strings
1. In the .aspx file, include an @ OutputCache directive with the required Duration and VaryByParam attributes. The Duration attribute must be set to any integer greater than zero. If you do not want to use the functionality provided by the VaryByParam attribute, set its value to None.
2. In the body of the @ OutputCache directive, include the VaryByCustom attribute that is set to the string that you want to vary the output cache by. The following directive varies the page output by the custom string "minorversion".
<%@ OutputCache Duration="10" VaryByParam="None" VaryByCustom="minorversion" %>
3. In a code-declaration block in your application's global.asax file, override the GetVaryByCustomString method to specify the behavior of the output cache for the custom string.
To cache multiple versions of page output programmatically, based on custom strings
1. In the page's code-declaration block or code-behind class, use Response.Cache syntax to set the expiration and visibility policies for the cached page content. You accomplish this by using the HttpCachePolicy.SetExpires and HttpCachePolicy.SetCacheability methods, respectively. For more information, see Setting Expirations for Page Caching and Setting the Cacheability of a Page.
2. In the same code, specify the custom string in the custom parameter of the SetVaryByCustom method. The following code sets the custom string to "minorversion".
3. [C#]
4. Response.Cache.SetVaryByCustom("minorversion");
5. [Visual Basic]
Response.Cache.SetVaryByCustom("minorversion")
6. In a code-declaration block in your application's Global.asax file, override the GetVaryByCustomString method to specify the behavior of the output cache for the custom string.
The following example demonstrates a simple Global.asax file that overrides the GetVaryByCustomString method when a page in the application passes the custom string minorversion to it.
[C#]
<script>
public override string GetVaryByCustomString(HttpContext context, string arg){
If (arg = "minorversion"){
Return "Version=" + context.Request.Browser.MinorVersion.ToString();
}
}
</script>
[Visual Basic]
<script>
Public Overrides Function GetVaryByCustomString(context As HttpContext, arg As String) As String
If (arg = "minorversion") Then
return "Version=" & context.Request.Browser.MinorVersion.ToString()
End If
End Function
</script>
The following example is a page that interacts with the previous Global.asax file to vary the output cache by the minorversion custom string.
Note This sample page uses declarative syntax to vary the output cache. If you want to do this programmatically, place code similar to that shown in Setting Expirations for Page Caching between the opening and closing tags of the < script> element.
[C#]
<%@ OutputCache Duration="30" VaryByParam="none" VaryByCustom="minorversion" %>
<Script language="C#" runat="server">
public void Page_Load(Object sender, EventArgs e) {
browserversion.InnerHtml = Request.Browser.MinorVersion.ToString();
timestamp.InnerHtml = DateTime.Now.ToString("r");
}
</Script>
Varying output by custom string (querystring value): <B id="browserversion" runat="server"/>
<BR>
Added to the cache: <B id="timestamp" runat="server" />
[Visual Basic]
<%@ Page Language="VB" %>
<%@ OutputCache Duration="30" VaryByParam="none" VaryByCustom="minorversion" %>
<Script runat="server">
Public Sub Page_Load
browserversion.InnerHtml = Request.Browser.MinorVersion.ToString()
timestamp.InnerHtml = DateTime.Now.ToString("r")
End Sub
</Script>
Varying output by browser: <B id="browserversion" runat="server"/>
<BR>
Added to the cache: <B id="timestamp" runat="server" />
When the page in this example is requested with a different value passed to the HttpBrowserCapabilities.MinorVersion property value, a different version of the page output is cached for each browser that makes a request. For example, a request from an Internet Explorer 5 browser causes one version to be cached, while a request from an Internet Explorer 5.5 browser causes another to be cached.
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.
[C#]
[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.
[C#]
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
[C#]
<%@ 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
[C#]
<% @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
[C#]
<%@ 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
[C#]
<% @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) %>
Caching Multiple Versions of User Control Output
Just as you can vary the versions of a page that are output-cached, you can output-cache regions of a page with user controls. You can do this by varying the user control output by the control's name and GET query string or form POST parameter values, or by parameter values alone. You can also cache multiple versions of a user control on a page by declaring it more than once in its containing .aspx file. You can use any of these techniques, whether you specify output caching for the user control with the @ OutputCache directive in the .ascx file or with the PartialCachingAttribute when you develop the user control in a code-behind class.
The @ OutputCache directive for user controls supports four attributes, VaryByParam, VaryByCustom, VaryByControl, and Shared. The PartialCachingAttribute class includes four properties, VaryByParams VaryByControls, VaryByCustom, and Shared, that allow you to use the same techniques by adding an attribute to a user control in a code-behind class.
When an ASP.NET page that contains a user control with output-cache settings is first requested, an instance of the control's output is saved to memory. By default, each page that contains the same user control will add another instance of the control's output to memory when it is requested.
For example, if you created a user control named sample.ascx with output-cache settings and added sample.ascx to 25 ASP.NET pages in your application, there would be at least that many versions of sample.ascx stored in the output cache. In addition, if you use the VaryByControl, VaryByCustom, or VaryByParam attribute to modify the caching behavior of the user control, there could be many more versions of user control output in the cache. For example, assume that you include a TextBox Web server control in your user control and set its ID property to MyTextBox . If you set the VaryByControl attribute to MyTextBox, there will be a version of user control output stored in the cache for every value that the MyTextBox control receives.
If the same user control is used in multiple pages within the same application, you can save memory by setting the Shared attribute of the user control's @ OutputCache directive to true or setting the PartialCachingAttribute.Shared property to true. This means that each page will access the same instance of user control output. Using the Shared property in commonly used and frequently cached user controls can save a significant amount of memory.
There is a major difference between adding user-control output to the output cache and doing the same for page output. While the output cache for both supports using GET query string and form POST parameters to create and cache multiple versions of output, user controls do not support caching based on HTTP headers.
There are four techniques you can use to vary output-cached user controls:
· You can use the VaryByParam attribute or the PartialCachingAttribute.VaryByParams property, which provide the same functionality as that provided for page output caching. You can set either to any string, but you need to make it equal to the GET query string or form POST parameters that are associated with the user control you create.
· You can use the VaryByControl attribute or PartialCachingAttribute.VaryByControls property to vary the output-cached user control according to the ID of an ASP.NET server control contained by the user control.
· You can use the VaryByCustom attribute or PartialCachingAttribute.VaryByCustom property to define code for a custom string that you want to vary the cached user control output by. This works in the same manner as the VaryByCustom technique for varying page output caching. For more information, see Caching Versions of a Page, Based on Custom Strings.
· You can include multiple instances of a user control in an ASP.NET page. Unless you set the Shared attribute of the @ OutputCache directive to true, output for each instance of the control will be cached.
For detailed information on each of these topics, see Caching Multiple Versions of a User Control, Based on Parameters and Caching Multiple Versions of a User Control Using Declarative Attributes.
Caching Multiple Versions of a User Control Based on Parameters
You can vary user-control output to the cache in two ways: by specifying the user control name along with either a query string or a form POST parameter, or by specifying the ID property of an ASP.NET server control contained in the user control. For the former, use the VaryByParam attribute of the @ OutputCache directive or include the VaryByParams property in the PartialCachingAttribute located in the user control's code-behind file. For the latter, use the VaryByControl attribute or include the VaryByControls property in the PartialCachingAttribute.
Note Varying user control output to the cache based on query string or form POST parameters will work only if the user control posts back and processes the postback itself. You cannot post back to the containing page and expect this type of caching of user control output to function properly.
To cache multiple versions of a user control declaratively by using the VaryByControl attribute
1. Create a user control that posts back.
2. Include an @ OutputCache directive in the .ascx file with Duration and VaryByControl attributes.
Note If you use the VaryByControl attribute in the directive, you do not need to also include the VaryByParam attribute.
3. Set the VaryByControl attribute to the ID attribute value for a control that is contained in the user control.
For example, the following @ OutputCache directive sets expirations for the user control to 60 seconds and varies the control's output by an ASP.NET server control with an ID property value of State.
<%@ OutputCache Duration="60" VaryByControl="State" %>
To cache multiple versions of a user control programmatically by using the VaryByControls property
1. In a code-behind class, create a user control code that posts back to itself.
2. Include a metadata PartialCaching attribute at the beginning of the user control code.
3. Include a value for the duration parameter and set the varyByControls parameter to the ID property value of the ASP.NET server control in the user control that you want to vary the user control output by.
When included before the code that extends the UserControl class, the following example sets duration to 60 seconds and varyByControls to "State".
[C#]
[PartialCaching(60, null, State, null)]
[Visual Basic]
<PartialCaching(60, null, State, null)>
To cache multiple versions of a user control declaratively by using the VaryByParam attribute
1. Create a user control that posts back to itself.
2. Include an @ OutputCache directive in the .ascx file with Duration and VaryByParam attributes.
Note If you include the VaryByControl attribute in the @ OutputCache directive for a user control, you do not need to also include the VaryByParam attribute. Regardless of which attribute you include, set its value to None if you do not want to use the functionality it provides.
3. Set the VaryByParam attribute to the GET query string or form POST parameter that you want to vary the user control by.
For example, the following @ OutputCache directive sets expirations for the user control to 60 seconds and varies the control's output by a State form POST or query string parameter.
<%@ OutputCache Duration="60" VaryByParam="State" %>
To cache multiple versions of a user control programmatically by using the VaryByParams property
1. In a code-behind class, create a user control code that posts back to itself.
2. Include a metadata PartialCaching attribute at the beginning of the user control code.
3. Include a value for the duration parameter and set the varyByParams parameter to the GET query string or form POST parameter that you want to vary the user control output by.
When included before the code that extends the UserControl class, the following example sets duration to 60 seconds and varyByParams to a State form POST or query string parameter.
[C#]
[PartialCaching(60, State, null, null)]
[Visual Basic]
<PartialCaching(60, State, null, null)>
The following example demonstrates a user control that posts back to itself by including the code for a ServerClick event in the code declaration block of the control. It also demonstrates using the VaryByControl parameter to vary user control output to the output cache, based on the State and Country form ID property values associated with the two DropDownList Web server controls contained in the user control. Also included is the Shared attribute, set to true to allow multiple pages to access the same cached user control output. It also includes a simple .aspx file that contains the user control. To use this example, name the user control file Sample.ascx .
[sample.ascx]
[C#]
<%@ Control Language="C#" %>
<%@ OutputCache Duration="30" VaryByControl="State;Country" Shared="true" %>
<%@ import namespace="System.Globalization"%>
<script runat=server>
void SubmitBtn_Click(Object Sender, EventArgs e) {
Label1.Text="You chose: " + state.SelectedItem.Text + " and " + country.SelectedItem.Text;
TimeMsg.Text = DateTime.Now.ToString("T");
}
</script>
<asp:DropDownList id="state" runat="server">
<asp:ListItem> </asp:ListItem>
<asp:ListItem>Idaho</asp:ListItem>
<asp:ListItem>Montana</asp:ListItem>
<asp:ListItem>Nevada</asp:ListItem>
<asp:ListItem>Oregon</asp:ListItem>
<asp:ListItem>Washington</asp:ListItem>
<asp:ListItem>Wyoming</asp:ListItem>
</asp:DropDownList>
<br>
<asp:DropDownList id="country" runat="server">
<asp:ListItem> </asp:ListItem>
<asp:ListItem>Austria</asp:ListItem>
<asp:ListItem>France</asp:ListItem>
<asp:ListItem>Italy</asp:ListItem>
<asp:ListItem>Germany</asp:ListItem>
<asp:ListItem>Spain</asp:ListItem>
<asp:ListItem>Switzerland</asp:ListItem>
</asp:DropDownList>
<br>
<asp:button text="Submit" OnClick="SubmitBtn_Click" runat=server/>
<br>
<asp:Label id=Label1 font-name="Verdana" font-size="10pt" runat="server">
Select values from the lists
</asp:Label>
<br> <br>
Control generated at: <asp:label id="TimeMsg" runat="server" />
[Visual Basic]
<%@ Language="VB" %>
<%@ OutputCache Duration="30" VaryByControl="State;Country" Shared="true" %>
<%@ import namespace="System.Globalization"%>
<script runat=server>
Sub SubmitBtn_Click(Sender as Object, e as EventArgs)
Label1.Text="You chose: " & state.SelectedItem.Text & " and " & country.SelectedItem.Text
TimeMsg.Text = DateTime.Now.ToString("T")
End Sub
</script>
<asp:DropDownList id=state runat="server">
<asp:ListItem> </asp:ListItem>
<asp:ListItem>Idaho</asp:ListItem>
<asp:ListItem>Montana</asp:ListItem>
<asp:ListItem>Nevada</asp:ListItem>
<asp:ListItem>Oregon</asp:ListItem>
<asp:ListItem>Washington</asp:ListItem>
<asp:ListItem>Wyoming</asp:ListItem>
</asp:DropDownList>
<br>
<asp:DropDownList id=country runat="server">
<asp:ListItem> </asp:ListItem>
<asp:ListItem>Austria</asp:ListItem>
<asp:ListItem>France</asp:ListItem>
<asp:ListItem>Italy</asp:ListItem>
<asp:ListItem>Germany</asp:ListItem>
<asp:ListItem>Spain</asp:ListItem>
<asp:ListItem>Switzerland</asp:ListItem>
</asp:DropDownList>
<br>
<asp:button text="Submit" OnClick="SubmitBtn_Click" runat=server/>
<br>
<asp:Label id=Label1 font-name="Verdana" font-size="10pt" runat="server">
Select values from the lists
</asp:Label>
<br> <br>
Control generated at: <asp:label id="TimeMsg" runat="server" />
</script>
[sample.aspx]
<%@ Register TagPrefix="Sample" TagName="Places"
Src="sample.ascx" %>
<form runat=server>
<Sample:Places id="Control1" runat=server />
</form>
Caching Multiple Versions of a User Control by Using Declarative Attributes
You can cache multiple versions of a user control by simply declaring it in an .aspx file more than once. Just as with user controls that are not output-cached, you can include a user control in an ASP.NET page as many times as needed for your application. Unless you set the Shared attribute or property to true for the user control, multiple versions of the control output will be stored in the cache.
To cache multiple versions of a user control by using declarative attributes
1. Using either the @ OutputCache directive in an .ascx file or the PartialCachingAttribute attribute in the code-behind class, specify the output cache settings for the user control.
2. Include multiple versions of the user control in a page, including the property you defined in the class as an attribute in the element. Make sure the property values are unique on the page.
This technique can be useful if you define attributes for a user control that customizes the output of the user control depending on the value that is assigned to that attribute. The following example demonstrates this. If you use the following as the .aspx page that contains a user control, you can use the State attribute on the user control declarations to generate different versions of the user control, one for CA and one for UT.
<%@ Register TagPrefix="MyControl" TagName="StateSort" Src="fragcache.ascx" %>
<form runat="server" >
<p>This page was generated at <%=DateTime.Now%>.
<br>
<MyControl:StateSort State="CA" runat="server" />
<br>
<MyControl:StateSort State="UT" runat="server" />
</form>
The user control, fragcache.ascx, contains the State property, which allows you to include the attribute in the user control server tags in the page.
[C#]
<%@ OutputCache Duration="120" VaryByParam="None" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script language="C#" runat=server>
public String State;
void Page_Load(Object sender, EventArgs e) {
String selectCmd = "select * from Authors where state = @State";
SqlConnection myConnection = new SqlConnection("server=(local)\\NetSDK;database=pubs;Trusted_Connection=yes");
SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection);
myCommand.SelectCommand.Parameters.Add(new SqlParameter("@State", SqlDbType.NVarChar, 2));
myCommand.SelectCommand.Parameters["@State"].Value = State;
DataSet ds = new DataSet();
myCommand.Fill(ds, "Authors");
MyDataGrid.DataSource= ds.Tables["Authors"].DefaultView;
MyDataGrid.DataBind();
}
</script>
<asp:datagrid id="MyDataGrid" runat="server" />
<br>
<p>This control was generated at <% =DateTime.Now %>.
[Visual Basic]
<%@ OutputCache Duration="120" VaryByParam="None" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script language="VB" runat="server">
Public State As String
Sub Page_Load(sender As Object, e As EventArgs)
Dim selectCmd As String = "select * from Authors where state = @State"
Dim myConnection As New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes")
Dim myCommand As New SqlDataAdapter(selectCmd, myConnection)
myCommand.SelectCommand.Parameters.Add(New SqlParameter("@State", SqlDbType.NVarChar, 2))
myCommand.SelectCommand.Parameters("@State").Value = State
Dim ds As New DataSet()
myCommand.Fill(ds, "Authors")
MyDataGrid.DataSource = ds.Tables("Authors").DefaultView
MyDataGrid.DataBind()
End Sub 'Page_Load
</script>
<asp:datagrid id="MyDataGrid" runat=server/>
<br>
<p>This control was generated at <% =DateTime.Now %>.
Simply including the @ OutputCache directive with a valid duration value in the .ascx file allows varied cache output of this user control.
ASP.NET has a powerful, easy-to-use caching mechanism that allows you to store objects that require a large amount of server resources to create in memory. It is implemented by the Cache class, with instances private to each application, and its lifetime is tied to that of the application. When the application is restarted, the Cache object is recreated.
The Cache class has been designed for ease of use. By using keys paired with values, you can place items in the Cache and later retrieve them. For examples of how to do this, see Adding Items to the Cache and Retrieving Values of Cached Items.
While the Cache class offers a simple interface for you to customize cache settings, it also offers powerful features that allow you to customize how items are cached and how long they are cached. For example, when system memory becomes scarce, the cache automatically removes seldom used or unimportant items to allow memory to be used to process a high volume of requests. This technique is called scavenging. It is one of the ways that the cache ensures that data that is not current does not consume valuable server resources.
You can instruct the Cache to give certain items priority over other items when it performs scavenging. To indicate that a specific item is of greater or lesser importance than another, specify one of the CacheItemPriority enumeration values when you add an item using the Cache.Add method or Cache.Insert method.
You can also establish an expiration policy for an item when you add it to the Cache using the Add method or Insert method. You can define the lifetime for an item by using the absoluteExpiration parameter, which is of the type DateTime and allows you to specify the exact time the item will expire. You can also use the slidingExpiration parameter, which is of the type TimeSpan. It allows you to specify the elapsed time before the item expires based on the time it is accessed. Once the item expires, it is removed from the cache. Attempts to retrieve its value will return null unless the item is added to the Cache again.
For volatile items that are stored in the Cache, such as those that have regular data refreshes, or those that are valid for only a set amount of time, set an expiration policy that keeps those items in the Cache as long as their data remains current. For example, if you are writing an application that tracks sports scores by obtaining the data from a frequently updated Web site, you can cache the scores for a game as long as those scores do not change on the source Web site. In this case, you can set an expiration policy that is based on how often the Web site updates the scores. You can write code that determines if an up-to-date score is in the Cache. If the score is not up to date, the code can update the score from the source Web site.
Finally, ASP.NET allows you to define the validity of a cached item, based on an external file, a directory, or another cached item. These are called file dependencies and key dependencies. If a dependency changes, the cached item is invalidated and removed from the Cache. You can use this technique to remove items from the Cache when their data source changes. For example, if you write an application that processes financial data from an XML file and renders it in a graph, you can insert the data from the file in the Cache and maintain a dependency on that XML file. When the file is updated, the item is removed from the cache, your application rereads the file, and a new version of the item is inserted.
Note The Cache has no information about the content of the items it contains. It merely holds a reference to those objects. It also provides methods to track their dependencies and set expiration policies.
For more information on how to use these features, see Adding Items to the Cache.
There are three different techniques you can use to add an item to the Cache object. Depending on the requirements of your application, your choices can range from the simple to the complex.
If you want to take advantage of the scavenging, expiration, and dependency support offered by the Cache, you must use either the Cache.Insert method or the Cache.Add method.
Note The Add and Insert methods have the same signature, but there are subtle differences between them. First, calling the Add method returns an object that represents the cached item, while calling Insert does not. Second, their behavior is different if you call these methods and add an item to the Cache that is already stored there. The Insert method replaces the item, while the Add method fails.
To add an item to the Cache by specifying its key and value
· You can add items to the cache as you would add items to a dictionary by specifying the item's key and value. The following code adds the current Value property of a text box to the Cache.
· [Visual Basic]
· Cache("txt1") = txtName.value
· [C#]
Cache["txt1"] = txtName.value;
To add items to the Cache by using the Insert method
· The Insert method is overloaded, allowing you to define values for the parameters of the version that you are using. For example, to add only an item key and value, use the following code.
· [Visual Basic]
· Cache.Insert("MyData1", connectionString)
· [C#]
Cache.Insert("MyData1", connectionString);
To add items to the Cache by using the Add method
· The Add method has the same signature as the Insert method, but it returns an object representing the item you added.
· [Visual Basic]
· Cache.Add("MyData1", connectionString)
· [C#]
Cache.Add("MyData1", connectionString);
Both of these methods offer you a great deal of control over the conditions under which the item remains in the Cache. Both support making the cached item dependent on external files or directories, other keys within the Cache, or arrays of either. Adding an item to the Cache with a dependency creates an instance of the CacheDependency class, which tracks changes to the dependencies you define. If any of these dependencies change, including being deleted or moved, the item they are associated with is removed from the Cache.
To add an item to the Cache that has a dependency
· You can add an item to the Cache with a dependency by using the dependencies parameter in the Add or Insert method. The following example demonstrates using the Insert method to add an item with a dependency on an XML file to the Cache.
· [C#]
· Cache.Insert("MyData1", connectionString, new CacheDependency(Server.MapPath(\\myServer\myConfig.xml)));
· [Visual Basic]
Cache.Insert("MyData1", connectionString, new CacheDependency(Server.MapPath(\\myServer\myConfig.xml)))
To add an item to the Cache with expiration policies
· You can add an item to the Cache with expiration policies by using the absoluteExpiration parameter and the slidingExpiration parameter. You can define either an absolute expiration or a sliding expiration, but not both. When you define an expiration policy with one of the parameters mentioned, you must set the other parameter to zero. The Cache class defines two fields that do this automatically: NoAbsoluteExpiration and NoSlidingExpiration. Simply set the appropriate parameter to its corresponding field value when you define an absolute or sliding expiration. The following example uses the Insert method to add an item to the Cache with an absolute expiration of two minutes.
· [C#]
· Cache.Insert("MyData1", connectionString, null, DateTime.Now.AddMinutes(2), NoSlidingExpiration);
· [Visual Basic]
Cache.Insert("MyData1", connectionString, null, DateTime.Now.AddMinutes(2), NoSlidingExpiration)
The following code uses the Insert method to add an item to the Cache with a sliding expiration of 30 seconds.
[C#]
Cache.Insert("MyData1", connectionString, null, NoAbsoluteExpiration, TimeSpan.FromSeconds(30));
[Visual Basic]
Cache.Insert("MyData1", connectionString, null, NoAbsoluteExpiration, TimeSpan.FromSeconds(30))
Note When you set an absolute expiration, use the DateTime structure. When you set a sliding expiration, use the TimeSpan structure. Also, if you create a sliding expiration that is less than zero or more than a year, an ArgumentOutOfRangeException Class is thrown.
You can also use the Add or Insert method to define the relative importance of the cached item by specifying a value from the CacheItemPriority enumeration. These relative priorities help the Web server when it scavenges to free memory. It can remove lower priority items from the Cache before higher priority items.
To add an item to the Cache with priority settings
· You can add an item to the Cache with priority settings by using the priority parameter on the Add or Insert method. The following example uses the Add method to add an item to the Cache with a priority of High.
· [C#]
· Cache.Add("MyData1", connectionString, null, NoAbsoluteExpiration, TimeSpan.FromSeconds(30), CacheItemPriority.High, null);
· [Visual Basic]
Cache.Add("MyData1", connectionString, null, NoAbsoluteExpiration, TimeSpan.FromSeconds(30), CacheItemPriority.High, null)
These methods also allow you to notify your application when the item is removed from the cache, using the CacheItemRemovedCallback delegate. For a full example, see Notifying an Application When an Item Is Deleted from the Cache.
Retrieving Values of Cached Items
Retrieving data from the Cache is simple; you only need to specify the key and value that represent the data. You then write code to display the data on your page.
To retrieve the value of a cached item
· The following code creates a Source DataView object, attempts to retrieve cached data that is assigned a key of MyData1 , and assigns that data to Source. It then verifies that the data was still stored in the Cache and assigns Source as the DataSource property of a DataGrid Web server control named MyDataGrid . It then binds the data to MyDataGrid.
· [C#]
· DataView Source;
· Source = (DataView)Cache["MyData1"];
·
· if(Source != null ) {
· MyDataGrid.DataSource = Source;
· MyDataGrid.DataBind();
· }
· [Visual Basic]
· Dim Source As DataView
· Source = CType(Cache("MyData1"), DataView)
· If Not (Source Is Nothing) Then
· MyDataGrid.DataSource = Source
· MyDataGrid.DataBind()
End If
To check for the existence of an item in the Cache
· A more complex situation is how your application responds when a data source or data set is not in the Cache. The following example modifies the code in the previous procedure to check for the cached data. If it is not in the cache, the example recreates it and adds it to the Cache.
· [C#]
· DataView Source = (DataView)Cache["MyData1"];
· if (Source == null) {
· SqlConnection myConnection = new SqlConnection("server=localhost;Integrated Security=SSPI;database=pubs");
· SqlDataAdapter myCommand = new SqlDataAdapter("select * from Authors", myConnection);
·
· DataSet ds = new DataSet();
· myCommand.Fill(ds, "Authors");
·
· Source = new DataView(ds.Tables["Authors"]);
· Cache["MyData1"] = Source;
· }
· MyDataGrid.DataSource=Source;
· MyDataGrid.DataBind();
· [Visual Basic]
· Dim Source As DataView = CType(Cache("MyData1"), DataView)
· If Source Is Nothing Then
· Dim myConnection As New SqlConnection("server=localhost;Integrated Security=SSPI;database=pubs")
· Dim myCommand As New SqlDataAdapter("select * from Authors", myConnection)
·
· Dim ds As New DataSet()
· myCommand.Fill(ds, "Authors")
·
· Source = New DataView(ds.Tables("Authors"))
· Cache("MyData1") = Source
· End If
· MyDataGrid.DataSource = Source
MyDataGrid.DataBind()
There are several reasons for an item to be removed from an application's Cache. You can set expiration policies that determine the total amount of time the item remains in the cache (absolute expiration). You can also set expiration policies that are based on the amount of time that must pass following the previous time the item is accessed (sliding expiration). You can also specify files, directories, or keys that the item is dependent on. The item is removed from the Cache when those dependencies change. The server itself can remove an item from the Cache when it needs to free memory (scavenging). You have control over the priorities of cached items when this occurs. Any of these methods for removing items from the Cache are determined when you write code to add the item to the Cache using either the Cache.Add or Cache.Insert method. For more information, see Adding Items to the Cache.
Additionally, you can explicitly remove items from the Cache by using the Cache.Remove method. You can use this method in event-handler code to respond to user input or some other input from your application.
To delete an item from the Cache by using the Remove method
· The Remove method has one parameter that allows you to specify the key of the item you want to remove. For example, the following code removes an item assigned the MyData1 key.
· [Visual Basic]
· Cache.Remove("MyData1")
· [C#]
Cache.Remove("MyData1");
Notifying an Application When an Item Is Deleted from the Cache
ASP.NET provides the CacheItemRemovedCallback delegate. It defines the signature to use when you write event handlers to respond when an item is deleted from the cache. ASP.NET also provides the CacheItemRemovedReason enumeration, which you can use to make event handlers dependent upon the reason the item is deleted.
To notify an application when an item is deleted from the cache
1. Create a local variable that raises the event for the CacheItemRemovedCallback delegate. For example, the following code creates an onRemove local variable of type CacheItemRemovedCallback.
private static CacheItemRemovedCallback onRemove = null;
Note The variable must be of this type to be used in the onRemoveCallback parameter of the Cache.Add or Cache.Insert method in step four.
2. Create an event handler to respond when the item is removed from the cache. For example, the following code sets the static Boolean itemRemoved to true, and the static CacheItemRemovedReason reason to the value passed when the item is removed from the cache.
Note Using the members of the CacheItemRemovedReason enumeration to create conditional code for the method in this step is an option open to you.
[C#]
CacheItemRemovedReason reason;
public void RemovedCallback(string key, object value, CacheItemRemovedReason callbackreason) {
reason = r;
}
[Visual Basic]
Dim reason As CacheItemRemovedReason
Public Sub RemovedCallback(key As String, value As Object, reason As CacheItemRemovedReason)
reason = r
End Sub
Note This event handler must use the same signature as the CacheItemRemovedCallback delegate. This code assumes that you have created two static variables: itemRemoved of type Boolean and reason of type CacheItemRemovedReason .
3. Create an instance of the CacheItemRemovedCallback delegate that calls the event handler. The following code calls the method created in step two.
onRemove = new CacheItemRemovedCallback(this.RemovedCallback);
4. Add the item to the Cache by using either the Cache.Add method or Cache.Insert method. You must specify the local variable, created in step one, in the onRemoveCallback parameter. The following code uses the Insert method to add an item to the cache with a key of "MyData1" and a value of Source. It defines the onRemove variable in the onRemoveCallback parameter.
Cache.Insert("MyData1", Source, null, DateTime.Now.AddMinutes(2), NoSlidingExpiration, CacheItemPriority.High, onRemove);
When the item added in step four is removed from the Cache for any reason, the RemovedCallback method is called, and the code within it can be accessed to render new content to a requesting client or to notify your application in a way you choose as appropriate.
For a full, working example, see documentation for the CacheItemRemovedCallback delegate.
Article from Microsoft.