0% found this document useful (0 votes)
47 views

Caching Overview

ASP.NET provides three types of caching for web applications: output caching, fragment caching, and data caching. Output caching caches entire page responses. Fragment caching caches portions of page responses. Data caching caches arbitrary objects in memory across requests using ASP.NET's cache engine. Choosing an appropriate caching strategy can substantially improve performance by reducing the processing needed to generate dynamic content.

Uploaded by

Akhilesh Singh
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
47 views

Caching Overview

ASP.NET provides three types of caching for web applications: output caching, fragment caching, and data caching. Output caching caches entire page responses. Fragment caching caches portions of page responses. Data caching caches arbitrary objects in memory across requests using ASP.NET's cache engine. Choosing an appropriate caching strategy can substantially improve performance by reducing the processing needed to generate dynamic content.

Uploaded by

Akhilesh Singh
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 17

Caching Overview

Caching is a technique widely used in computing to increase performance by keeping frequently accessed or expensive
data in memory. In the context of a Web application, caching is used to retain pages or data across HTTP requests and
reuse them without the expense of recreating them.

ASP.NET has three kinds of caching that can be used by Web applications:

 Output caching, which caches the dynamic response generated by a request.


 Fragment caching, which caches portions of a response generated by a request.
 Data caching, which caches arbitrary objects programmatically. To support this, ASP.NET provides a full-
featured cache engine that allows programmers to easily retain data across requests.

Output caching is useful when the contents of an entire page can be cached. On a heavily accessed site, caching
frequently accessed pages for even a minute at a time can result in substantial throughput gains. While a page is cached
by the output cache, subsequent requests for that page are served from the output page without executing the code that
created it.

Sometimes it is not practical to cache an entire page - perhaps portions of the page must be created or customized for
each request. In this case, it is often worthwhile to identify objects or data that are expensive to construct and are
eligible for caching. Once these items are identified, they can be created once and then cached for some period of time.
Additionally, fragment caching can be used to cache regions of a page's output.

Choosing the time to cache an item can be an interesting decision. For some items, the data might be refreshed at
regular intervals or the data is valid for a certain amount of time. In that case, the cache items can be given an expiration
policy that causes them to be removed from the cache when they have expired. Code that accesses the cache item simply
checks for the absence of the item and recreates it, if necessary.

The ASP.NET cache supports file and cache key dependencies, allowing developers to make a cache item dependent on
an external file or another cache item. This technique can be used to invalidate items when their underlying data source
changes.

Page Output Caching

Output caching is a powerful technique that increases request/response throughput by caching the content generated
from dynamic pages. Output caching is enabled by default, but output from any given response is not cached unless
explicit action is taken to make the response cacheable.

To make a response eligible for output caching, it must have a valid expiration/validation policy and public cache visibility.
This can be done using either the low-level OutputCache API or the high-level @ OutputCache directive. When output
caching is enabled, an output cache entry is created on the first GET request to the page. Subsequent GET or HEAD
requests are served from the output cache entry until the cached request expires.

The output cache also supports variations of cached GET or POST name/value pairs.

The output cache respects the expiration and validation policies for pages. If a page is in the output cache and has been
marked with an expiration policy that indicates that the page expires 60 minutes from the time it is cached, the page is
removed from the output cache after 60 minutes. If another request is received after that time, the page code is
executed and the page can be cached again. This type of expiration policy is called absolute expiration - a page is valid
until a certain time.

The following example demonstrates a simple way to output cache responses using the @ OutputCache directive. The
example simply displays the time when the response was generated. To see output caching in action, invoke the page
and note the time at which the response was generated. Then refresh the page and note that the time has not changed,
indicating that the second response is being served from the output cache.

CS\outputcache1.aspx
<%@ OutputCache Duration="60" VaryByParam="none" %>
<html>

<script language="C#" runat="server">

void Page_Load(Object sender, EventArgs e) {


TimeMsg.Text = DateTime.Now.ToString("G");
}

</script>

<body>

<h3><font face="Verdana">Using the Output Cache</font></h3>

<p><i>Last generated on:</i> <asp:label id="TimeMsg"


runat="server"/>

</body>

</html>

The following directive activates output caching on the response:

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


This directive simply indicates that the page should be cached for 60 seconds and that the page does not vary by any
GET or POST parameters. Requests received while the page is still cached are satisfied from the cache. After 60 seconds,
the page is removed from the cache; the next request is handled explicitly and caches the page again.

Of course, in the previous example, very little work is saved by output caching. The following example shows the same
technique for output caching, but queries a database and displays the results in a grid.

CS\outputcache2.aspx
<%@ OutputCache Duration="60" VaryByParam="none" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>

<html>

<script language="C#" runat="server">

void Page_Load(Object Src, EventArgs E ) {

SqlConnection myConnection = new


SqlConnection("server=(local)\\NetSDK;database=pubs;Trusted_Connection=y
es");
SqlDataAdapter myCommand = new SqlDataAdapter("select * from
Authors", myConnection);

DataSet ds = new DataSet();


myCommand.Fill(ds, "Authors");

MyDataGrid.DataSource=new DataView(ds.Tables[0]) ;
MyDataGrid.DataBind();

TimeMsg.Text = DateTime.Now.ToString("G");
}

</script>

<body>

<h3><font face="Verdana">Using the Output Cache</font></h3>

<ASP:DataGrid id="MyDataGrid" runat="server"


Width="700"
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" />

</body>
</html>

In the final example, the application is modified slightly to allow the user to selectively query for authors in various states.
This example demonstrates caching requests varying by the name/value pairs in the query string using the
VaryByParam attribute of the @ OutputCache directive.

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


For each state in the data set, there is a link that passes the desired state as part of the query string. The application
then constructs the appropriate database query and shows authors belonging only to the selected state.

Note that the first time you click the link for a given state, it generates a new timestamp at the bottom of the page.
Thereafter, whenever a request for that state is resubmitted within a minute, you get the original timestamp indicating
that the request has been cached.

CS\outputcache3.aspx
<%@ OutputCache Duration="60" VaryByParam="state" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>

<html>

<script language="C#" runat="server">

void Page_Load(Object Src, EventArgs E ) {

String selectCmd;
String state = Request["state"];

if( state == null ) {


selectCmd = "select * from Authors";
}
else {
selectCmd = "select * from Authors where state = '" + state
+ "'";
}

SqlConnection myConnection = new


SqlConnection("server=(local)\\NetSDK;database=pubs;Trusted_Connection=y
es");
SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd,
myConnection);

DataSet ds = new DataSet();


myCommand.Fill(ds, "Authors");

MyDataGrid.DataSource=new DataView(ds.Tables[0]);
MyDataGrid.DataBind();

// capture the time of the current request


// subsequent requests that are cached will show the
// original time

TimeMsg.Text = DateTime.Now.ToString("G");
}

</script>

<body>
<h3><font face="Verdana">Using the Output Cache</font></h3>

<b>Authors by State:</b>

<table cellspacing="0" cellpadding="3" rules="all"


style="background-color:#AAAADD;border-color:black;border-
color:black;width:700px;border-collapse:collapse;">
<tr>
<td><a href="outputcache3.aspx?state=CA">CA</a></td>
<td><a href="outputcache3.aspx?state=IN">IN</a></td>
<td><a href="outputcache3.aspx?state=KS">KS</a></td>
<td><a href="outputcache3.aspx?state=MD">MD</a></td>
<td><a href="outputcache3.aspx?state=MI">MI</a></td>
<td><a href="outputcache3.aspx?state=OR">OR</a></td>
<td><a href="outputcache3.aspx?state=TN">TN</a></td>
<td><a href="outputcache3.aspx?state=UT">UT</a></td>
</tr>
</table>

<p>

<ASP:DataGrid id="MyDataGrid" runat="server"


Width="700"
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"/>

</body>
</html>

Applications that want more control over the HTTP headers related to caching can use the functionality provided by the
System.Web.HttpCachePolicy class. The following example shows the code equivalent to the page directives used in
the previous samples.

C#
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
VB
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60))
Response.Cache.SetCacheability(HttpCacheability.Public)
JSCRIPT
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);

To make this a sliding expiration policy, where the expiration time out resets each time the page is requested, set the
SlidingExpiration property as shown in the following code.

C#
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetSlidingExpiration(true);
VB
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60))
Response.Cache.SetCacheability(HttpCacheability.Public)
Response.Cache.SetSlidingExpiration(True)
JSCRIPT
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetSlidingExpiration(true);

Note: When sliding expiration is enabled (SetSlidingExpiration(true)), a request made to the origin server always
generates a response. Sliding expiration is useful in scenarios where there are downstream caches that can satisfy client
requests, if the content has not expired yet, without requesting the content from the origin server.

Applications being ported from ASP may already be setting cache policy using the ASP properties; for example:

C#
Response.CacheControl = "Public";
Response.Expires = 60;
VB
Response.CacheControl = "Public"
Response.Expires = 60
JSCRIPT
Response.CacheControl = "Public";
Response.Expires = 60;
These properties are supported by ASP.NET and have the same effect as the other examples that have been shown.

Section Summary

1. Output caching caches the content generated by ASP.NET pages.


2. Pages are not placed in the output cache unless they have a valid expiration or validation policy and public
cache visibility.

Page Fragment Caching

In addition to output caching an entire page, ASP.NET provides a simple way for you to output cache regions of page
content, which is appropriately named fragment caching. You delineate regions of your page with a user control, and
mark them for caching using the @ OutputCache directive introduced in the previous section. This directive specifies the
duration (in seconds) that the output content of the user control should be cached on the server, as well as any optional
conditions by which it should be varied.

For example, the following directive instructs ASP.NET to output cache the user control for 120 seconds, and to vary the
caching using the "CategoryID" and "SelectedID" querystring or form post parameters.

<%@ OutputCache Duration="120" VaryByParam="CategoryID;SelectedID"%>

The VaryByParam attribute is extremely powerful and allows user control authors to instruct ASP.NET to cache/store
multiple instances of an output cache region on the server. For example, the following URLs to the host page of the
previous user control cache separate instances of the user control content.

http://localhost/mypage.aspx?categoryid=foo&selectedid=0
http://localhost/mypage.aspx?categoryid=foo&selectedid=1

Logic within a user control can then dynamically generate different content (which is cached separately) depending on
the arguments provided.

In addition to supporting the VaryByParam attribute, fragment caching also supports a VaryByControl attribute.
Whereas the VaryByParam attribute varies cached results based on name/value pairs sent using POST or GET, the
VaryByControl attribute varies the cached fragment by controls within the user control. For example:

<%@ OutputCache Duration="120" VaryByParam="none"


VaryByControl="Category" %>

Note that similar to output-cached pages, explict use of VaryByParam is required even if it is not used.

If the user control contained a drop-down select box control named Category, the user control's output would vary based
on the selected value within that control.

Just as it is possible to nest user controls recursively within a page (that is, a user control declared within another server
control), it is also possible to nest output-cached user controls recursively. This provides a powerful composition model
that enables cached regions to be composed of further subcached regions.

The following sample code demonstrates how to cache two menu sections of a page using a declarative user control.

C#
<%@ Register TagPrefix="Acme" TagName="Menu" Src="Menu.ascx" %>

<html>
<body>
<table>
<tr>
<td>
<Acme:Menu Category="LeftMenu" runat=server/>
</td>
<td>
<h1>Hi, the time is now: <%=DateTime.Now%> </h1>
</td>
<td>
<Acme:Menu Category="RightMenu" runat=server/>
</td>
<tr>
</table>
</body>
</html>
VB
<%@ Register TagPrefix="Acme" TagName="Menu" Src="Menu.ascx" %>

<html>
<body>
<table>
<tr>
<td>
<Acme:Menu Category="LeftMenu" runat=server/>
</td>
<td>
<h1>Hi, the time is now: <%=Now%> </h1>
</td>
<td>
<Acme:Menu Category="RightMenu" runat=server/>
</td>
<tr>
</table>
</body>
</html>
JSCRIPT
<%@ Register TagPrefix="Acme" TagName="Menu" Src="Menu.ascx" %>

<html>
<body>
<table>
<tr>
<td>
<Acme:Menu Category="LeftMenu" runat=server/>
</td>
<td>
<h1>Hi, the time is now: <%=DateTime.Now%> </h1>
</td>
<td>
<Acme:Menu Category="RightMenu" runat=server/>
</td>
<tr>
</table>
</body>
</html>
The following sample code shows the implementation of the "Acme:Menu" user control with caching support.

C#
<%@ OutputCache Duration="120" VaryByParam="none" %>

<script language="C#" runat=server>

public String Category;

void Page_Load(Object sender, EventArgs e) {

AdoConnection conn = new AdoConnection("MyDSN");

MyMenu.DataSource = conn.Execute("select * from menu where


category=" + Category );
MyMenu.DataBind();
}

</script>

<asp:datagrid id="MyMenu" runat=server/>


VB
<%@ OutputCache Duration="120" VaryByParam="none" %>

<script language="VB" runat=server>

Public Category As String;

Sub Page_Load(sender As Object, e As EventArgs)

Dim conn As AdoConnection = New AdoConnection("MyDSN")

MyMenu.DataSource = conn.Execute("select * from menu where


category=" & Category)
MyMenu.DataBind()
End Sub

</script>

<asp:datagrid id="MyMenu" runat=server/>


JSCRIPT
<%@ OutputCache Duration="120" VaryByParam="none" %>

<script language="JScript" runat=server>

public var Category:String;

function Page_Load(sender:Object, e:EventArgs) : void {

var conn:AdoConnection = new AdoConnection("MyDSN");

MyMenu.DataSource = conn.Execute("select * from menu where


category=" + Category );
MyMenu.DataBind();
}
</script>

<asp:datagrid id="MyMenu" runat=server/>

Note that this example output caches the response of each user control for a period of 120 seconds. All logic necessary to
recreate each menu user control in the event of a cache miss (either because 120 seconds has expired or because
memory conditions on the server have become scarce) is encapsulated cleanly within the user control.

The following example shows simple fragment caching. The sample caches the output from a control that retrieves data
from an SQL Server database, while keeping the dynamic properties of the parent page. You can see that the page is
dynamic because the time is updated with every refresh, while the control is only updated every 60 seconds.

CS\fragmentcache1.aspx
<%@ Register TagPrefix="Acme" TagName="DataControl" Src="datactrl.ascx"
%>

<html>

<script language="C#" runat="server">

void Page_Load(Object Src, EventArgs E ) {

TimeMsg.Text = DateTime.Now.ToString("G");
}

</script>

<body>

<h3><font face="Verdana">Fragment Caching</font></h3>

<Acme:DataControl runat="server"/>

<br>

<i>Page last generated on:</i> <asp:label id="TimeMsg"


runat="server" />

</body>
</html>
CS\datactrl.ascx
<%@ OutputCache Duration="60" VaryByParam="none" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>

<script language="C#" runat="server">

void Page_Load(Object Src, EventArgs E ) {

SqlConnection myConnection = new


SqlConnection("server=(local)\\NetSDK;database=pubs;Trusted_Connection=y
es");
SqlDataAdapter myCommand = new SqlDataAdapter("select * from
Authors", myConnection);

DataSet ds = new DataSet();


myCommand.Fill(ds, "Authors");

MyDataGrid.DataSource=new DataView(ds.Tables[0]) ;
MyDataGrid.DataBind();

TimeMsg.Text = DateTime.Now.ToString("G");
}

</script>

<ASP:DataGrid id="MyDataGrid" runat="server"


Width="700"
BackColor="#ccccff"
BorderColor="black"
ShowFooter="false"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
/>

<p>

<i>Control last generated on:</i> <asp:label id="TimeMsg"


runat="server" />

Caveats
Note: Attempts to programmatically manipulate an output-cached control from its containing page result in an error. For
example, attempts to use a declarative data binding expression on the user control tag generates parser errors, as shown
in the following code.

<!-- The following tags generate parser errors. -->


<Acme:Menu Category='<%# Container.DataItem("Category")'
runat="server"/>

The reason for this is simple. In cases when the content of a user control is output cached, an instance of the control is
created only on the first request; thus, once cached, the control is no longer available. Instead, you should encapsulate
all the logic necessary to create the content of a user control directly within the control itself; this is typically done within
the user control's Page_Load event or Page_PreRender event.

You can declare and use other declarative property parameters to customize the control. For example, the previous user
control can be customized as follows:

<Acme:Menu Category="LeftMenu" runat=server/>


<Acme:Menu Category="RightMenu" runat=server/>

These declarations cause the appropriate code to be generated and executed by the page compiler in the event that the
control is created as a result of a cache miss. User control developers can then access these settings just as they would in
a non-cached user control scenario.

Section Summary
1. In addition to output caching an entire page, ASP.NET provides a simple way for you to output cache regions of
page content, which is appropriately named fragment caching.
2. You delineate regions of your page with a user control and mark them for caching using the @ OutputCache
directive introduced in the previous section.
3. Just as it is possible to nest user controls recursively within a page (that is, a user control declared within
another server control), it is also possible to nest output-cached user controls recursively.
4. Attempts to programmatically manipulate an output-cached control from its containing page result in an error.
Instead, you should encapsulate all the logic necessary to create the content of a user control directly within
the control itself, typically within the user control's Page_Load event or Page_PreRender event.
5. It is possible to declare and use other declarative property parameters to customize the control.

Page Data Caching

  Introduction to Data Caching


  Using the Data Cache
  Section Summary

Introduction to Data Caching

ASP.NET provides a full-featured cache engine that can be used by pages to store and retrieve arbitrary objects across
HTTP requests. The ASP.NET cache is private to each application and stores objects in memory. The lifetime of the cache
is equivalent to the lifetime of the application; that is, when the application is restarted, the cache is recreated.

The cache provides a simple dictionary interface that allows programmers to easily place objects in and retrieve them
from the cache. In the simplest case, placing an item in the cache is just like adding an item to a dictionary:

C#
Cache["mykey"] = myValue;
VB
Cache("mykey") = myValue
JSCRIPT
Cache("mykey") = myValue;

Retrieving the data is just as simple:


C#
myValue = Cache["mykey"];
if(myValue != null ) {
DisplayData(myValue);
}
VB
myValue = Cache("mykey")
If myValue <> Null Then
DisplayData(myValue)
End If
JSCRIPT
myValue = Cache("mykey");
if(myValue != null ) {
DisplayData(myValue);
}

For applications that need more sophisticated functionality, the ASP.NET cache supports scavenging, expiration, and file
and key dependencies.

 Scavenging means that the cache attempts to remove infrequently used or unimportant items if memory
becomes scarce. Programmers who want to control how scavenging occurs can provide hints to the scavenger
when items are inserted into the cache that indicate the relative cost of creating the item and the relative rate
at which the item must be accessed to remain useful.
 Expiration allows programmers to give cache items lifetimes, which can be explicit (for example, expire at 6:00)
or can be relative to an item's last use (for example, expire 20 minutes after the item was last accessed). After
an item has expired, it is removed from the cache and future attempts to retrieve it return the null value unless
the item is reinserted into the cache.
 File and key dependencies allow the validity of a cache item to be based on an external file or on another cache
item. If a dependency changes, the cache item is invalidated and removed from the cache. For an example of
how you might use this functionality, consider the following scenario: an application reads financial information
from an XML file that is periodically updated. The application processes the data in the file and creates a graph
of objects that represent that data in a consumable format. The application caches that data and inserts a
dependency on the file from which the data was read. When the file is updated, the data is removed from the
cache and the application can reread it and reinsert the updated copy of the data.

Using the Data Cache

The following sample shows a simple use of the cache. It executes a database query and caches the result, which it
continues to use for the lifetime of the application. When you run the sample, note the message at the bottom of the
page. When first requested, it indicates that the data was explicitly retrieved from the database server. After refreshing
the page, the page notes that the cached copy was used.

CS\datacache1.aspx
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>

<html>

<script language="C#" runat="server">

void Page_Load(Object Src, EventArgs E) {

DataView Source;

// try to retrieve item from cache


// if it's not there, add it

Source = (DataView)Cache["MyDataSet"];

if (Source == null) {

SqlConnection myConnection = new


SqlConnection("server=(local)\\NetSDK;database=pubs;Trusted_Connection=y
es");
SqlDataAdapter myCommand = new SqlDataAdapter("select * from
Authors", myConnection);

DataSet ds = new DataSet();


myCommand.Fill(ds, "Authors");

Source = new DataView(ds.Tables["Authors"]);


Cache["MyDataSet"] = Source;

CacheMsg.Text = "Dataset created explicitly";


}
else {
CacheMsg.Text = "Dataset retrieved from cache";
}

MyDataGrid.DataSource=Source;
MyDataGrid.DataBind();
}

</script>

<body>

<form method="GET" runat="server">

<h3><font face="Verdana">Caching Data</font></h3>

<ASP:DataGrid id="MyDataGrid" runat="server"


Width="700"
BackColor="#ccccff"
BorderColor="black"
ShowFooter="false"
CellPadding=3
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaad" />

<p>

<i><asp:label id="CacheMsg" runat="server"/></i>

</form>
</body>
</html>

The next example shows a cache item that depends on an XML file. It is similar to the first example, although in this case
the data is retrieved from an XML data source instead of a database server. When the data is cached, the XML file is
added as a dependency.

When a new record is added using the form at the bottom of the page, the XML file is updated and the cached item must
be recreated.

CS\datacache2.aspx
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>

<html>

<script language="C#" runat="server">

void Page_Load(Object Src, EventArgs E ) {

if(!IsPostBack) {
LoadData();
}
}

void NewAuthorBtn_Click(Object sender, EventArgs E) {


if(!Page.IsValid) {
AuthorMsg.Text = "Some required fields are missing";
return;
}

DataSet ds = new DataSet();

// open the file and read the current data


FileStream fs = new
FileStream(Server.MapPath("authors.xml"),FileMode.Open, FileAccess.Read,
FileShare.ReadWrite);
StreamReader reader = new StreamReader(fs);
ds.ReadXml(reader);
fs.Close();

// append a row
try {
DataRow newAuthor = ds.Tables[0].NewRow();
newAuthor["au_id"] = AuthorId.Text;
newAuthor["au_lname"] = LastName.Text;
newAuthor["au_fname"] = FirstName.Text;
newAuthor["phone"] = Phone.Text;
newAuthor["address"] = Address.Text;
newAuthor["city"] = City.Text;
newAuthor["state"] = State.Text;
newAuthor["zip"] = PostalCode.Text;
newAuthor["contract"] = Contract.Checked;
ds.Tables[0].Rows.Add(newAuthor);
} catch(Exception) {
CacheMsg.Text = "Failed to create author with id = (" +
AuthorId.Text + ")<br>" + "Author already exists.";
return;
}

// rewrite the data file


fs = new FileStream(Server.MapPath("authors.xml"),
FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
TextWriter writer = new StreamWriter(fs);
writer = TextWriter.Synchronized(writer);
ds.WriteXml(writer);
writer.Close();

Cache.Remove("MyData");
LoadData();
}

void RefreshBtn_Click(Object sender, EventArgs e) {

LoadData();
}

void LoadData() {

DataView Source = (DataView)Cache["MyData"];

if(Source == null) {
// 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();

Source = new DataView(ds.Tables[0]);

// cache it for future use


Cache.Insert("MyData", Source, new
CacheDependency(Server.MapPath("authors.xml")));

// we created the data explicitly, so advertise that fact


CacheMsg.Text = "Dataset created explicitly";
}
else {
CacheMsg.Text = "Dataset retrieved from cache";
}

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="900"
BackColor="#ccccff"
BorderColor="black"
ShowFooter="false"
CellPadding=3
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
/>

<hr>

<h3><font face="Verdana">Add New Author</font></h3>

<asp:Label ID="AuthorMsg" Text="Fill in the required fields below


to add a new author" ForeColor="red" Font-Name="Verdana" Font-Size="10"
runat=server />

<p>

<table>
<tr>
<td>Author Id:</td>
<td><ASP:TextBox id=AuthorId Text="111-11-1111"
runat=server/></td>
<td><ASP:RequiredFieldValidator ControlToValidate="AuthorId"
Display="Static" ErrorMessage="*" runat=server/></td>
</tr>
<tr>
<td>Last Name:</td>
<td><ASP:TextBox id=LastName Text="Doe" runat=server/></td>
<td><ASP:RequiredFieldValidator ControlToValidate="LastName"
Display="Static" ErrorMessage="*" runat=server/></td>
</tr>
<tr>
<td>First Name:</td>
<td><ASP:TextBox id=FirstName Text="John" runat=server/></td>
<td><ASP:RequiredFieldValidator ControlToValidate="FirstName"
Display="Static" ErrorMessage="*" runat=server/></td>
</tr>
<tr>
<td>Phone:</td>
<td><ASP:TextBox id=Phone Text="555 555-5050"
runat=server/></td>
<td><ASP:RequiredFieldValidator ControlToValidate="Phone"
Display="Static" ErrorMessage="*" runat=server/></td>
</tr>
<tr>
<td>Address:</td>
<td><ASP:TextBox id=Address Text="One Microsoft Way"
runat=server/></td>
<td><ASP:RequiredFieldValidator ControlToValidate="Address"
ErrorMessage="*" Display="Static" runat=server/></td>
</tr>
<tr>
<td>City:</td>
<td><ASP:TextBox id=City Text="Redmond" runat=server/></td>
<td><ASP:RequiredFieldValidator ControlToValidate="City"
ErrorMessage="*" Display="Static" runat=server/></td>
</tr>
<tr>
<td>State:</td>
<td><ASP:TextBox id=State Text="WA" runat=server/></td>
<td><ASP:RequiredFieldValidator ControlToValidate="State"
ErrorMessage="*" Display="Static" runat=server/></td>
</tr>
<tr>
<td>Postal Code:</td>
<td><ASP:TextBox id=PostalCode Text="98052"
runat=server/></td>
<td><ASP:RequiredFieldValidator ControlToValidate="PostalCode"
ErrorMessage="*" Display="Static" runat=server/></td>
</tr>
<tr>
<td>Contract:</td>
<td><ASP:CheckBox id=Contract Checked runat="server"/></td>
<td></td>
</tr>
</table>

<asp:button Text="Add New Author" OnClick="NewAuthorBtn_Click"


runat=server/> <asp:button Text="Refresh List"
OnClick="RefreshBtn_Click" runat=server/>

<p>

<hr>

<p>

<i><asp:label id="CacheMsg" runat="server"/></i></p>

</form>
</body>
</html>

Note that a file dependency is added by using Cache.Insert and supplying a CacheDependency object referencing the
XML file.

Cache.Insert("MyData", Source,
new CacheDependency(Server.MapPath("authors.xml")));

A cache item can depend on a single or multiple files or keys. As mentioned previously, an application can also set
expiration policy on a cache item. The following code sets an absolute cache expiration time.

Cache.Insert("MyData", Source, null,


DateTime.Now.AddHours(1), TimeSpan.Zero);

The relevant parameter is the call to DateTime.Now.AddHours(1), which indicates that the item expires 1 hour from
the time it is inserted. The final argument, TimeSpan.Zero indicates that there is no relative expiration policy on this
item.

The following code shows how to set a relative expiration policy. It inserts an item that expires 20 minutes after it is last
accessed. Note the use of DateTime.MaxValue, which indicates that there is no absolute expiration policy on this item.

Cache.Insert("MyData", Source, null, DateTime.MaxValue,


TimeSpan.FromMinutes(20));

Section Summary

1. Data caching allows arbitrary objects to be cached programmatically.


2. The ASP.NET cache supports expiration and dependencies.
3. The cache is scoped to an application and its lifetime is equivalent to the lifetime of the application.

You might also like