You are on page 1of 16

If you're using typically static data with your ASP.

NET applications - such as that from a


database server like Microsoft SQL Server - you should take a look at caching your data.
Previously, this was not an easy thing to do, but the caching in .NET makes caching your
data and objects a trivial task. This tutorial will cover basic caching and scenarios where
caching would be good to use.

Using the Cache Property

In ASP.NET, every page you write extends the System.Web.UI.Page class, which
contains a member called Cache. You use the Cache property as you would any other
IEnumerable, which gives you methods and properties to get, set, and enumerate through
members. We will be looking at getting and setting items in the cache. In the simplest
example, you can retrieve any object from the cache like so:
Object obj = (Object)Cache["key"];

What this does is look in the Cache for an item with the key "key". If such an item exists,
the object is returned. While we don't need to cast the returned object to Object, this is
just an example of how you must cast the return to the class type you want returned. If
the item is not found, null is returned, so you will need to do some checking:
Object obj = (Object)Cache["key"];
if (obj == null) {
// Generate a new object and insert it into the cache
}
// Use your object

You can also assign object to the cache like the following code example, but using
Cache.Inset() is a much better means as you'll see later:
Cache["key"] = obj;

Now let's look at a serious example. In the example below, we will define a function that
binds data to a control, such as a ASP.NET DataGrid control. We will look at data binding
in a little more depth later. For this example, we will use a System.Data.DataSet object.
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data"
%>
<script runat="server">
private string _filename = "mydata.xml";

private void Page_Load(Object src, EventArgs args) {


DataSet ds = (DataSet)Cache["mydata"];
if (ds == null) {
ds.ReadXml(Server.MapPath(_filename));
Cache.Insert("mydata", ds,
new CacheDependency(Server.MapPath(_filename)),
DateTime.Now.AddHours(12), NoSlidingExpiration);
}
myDataGrid.DataSource = ds;
myDataGrid.DataBind();
}

We'll break down the above example. The first part we've already discussed, where we
get the object from the cache. If the object is null (i.e., doesn't exist in the cache), we
need to create the object. The first line after checking if our DataSet object is null loads
an XML file called a DiffGram, which is a serialized DataSet object. We'll talk about this
later. Essentially, the DataSet object (hereforth, "ds") is created from serialized XML,
which you can event type by hand. We call Server.MapPath() because the file as we know
it is virtual. ds.ReadXml needs the absolute path and filename to load it.
Server.MapPath() figures out what the absolute path of a virtual filename (such as your
web pages) and returns the absolute path.

The next statement inserts the newly created "ds" into the cache. Again, the statement is:
Cache.Insert("mydata", ds,
new CacheDependency(Server.MapPath(_filename)),
DateTime.Now.AddHours(12), NoSlidingExpiration);

1. The first parameter is the key used to identify our cache item.
2. The second parameter is the object we want to cache. In this example, we are
caching the DataSet object "ds". This can be any object, however, including
strings, numbers, controls, etc.
3. The third parameter creates a dependency on an object. If this object changes, the
cached object is marked as expired and your application will regenerate next time,
returning null as your object reference. In fact, the object is expired. You can also
pass null in this parameter to signify that you don't want any dependencies.
4. The fourth parameter is the absolute expiration period your object is valid. Here,
we use DateTime.Now (which uses "now's" time) and add 12 hours to it. This
means the object will automatically expire in 12 hours. You could also use
NoAbsoluteExpiration which means the object will never expire until the
dependent object changes. We use an absolute expiration here to make sure we
have somewhat recent data in case the CacheDependency doesn't expire the data
for some reason. (As if Microsoft software doesn't have bugs!)
5. The fifth and final parameter is a sliding expiration. This means that if the object
is access, the absolute expiration time is essentially pushed back to however many
minutes, hours, etc. you specify here. This is an object of type TimeSpan. Here,
we want our object expired after 12 hours even if the object is accessed before
then.

After all this, we can finally bind our object to a data-driven control, such as the
ASP.NET DataGrid control. While the full use of the control is out of the scope of this
tutorial, I will cover the usage in brief detail.
The DataGrid control is a data-driven control meaning that on the server, the control will
use data and will then render the HTML onto the page for the client to see in their
browser. We will define a basic DataGrid control customizing only a few parameters:
<body>
<asp:DataGrid id="myDataGrid" runat="server"
AutoGenerateColumns="true"
ShowHeader="true"
AllowPaging="true"
PageSize="25"
Font-Name="Verdana"
Font-Size="10pt">
<HeaderStyle Font-Bold="true"/>
</asp:DataGrid>
</body>

Please note: this example assumes you already have your other HTML tags setup and
that the DataGrid is the only control in the BODY, which it doesn't have to be.

Above, we define a Web server control of type DataGrid, which is a data-driven control
that renders a table on the page. By setting AutoGenerateColumns to true (which is
default anyway), we specify that the DataGrid control will automatically generate headers
and columns based on your data in the order of the columns in your DataSet. We also
setup default paging and a few items styles, while making the Header column text bold.

In the example Page_Load() event handler, we did a little data binding like so:
myDataGrid.DataSource = ds;
myDataGrid.DataBind();

These two lines associate the DataSource property of the DataGrid with our DataSet
object "ds" and then binds the data with DataBind(). If you do not call DataBind(), you
will find that nothing is rendered on your page. The DataSource property can point at
other types of object, like ArrayList(), DataView() and many others. Consult your .NET
SDK Documentation for more details.

Scenarios

Why would you use this tutorial to build your next data-driven ASP.NET page? There are
several examples, but I will discuss one here.

Lets say that you've developed a page or site that generates a table of contents on ever
page. You also have a SQL Server storing this data because the table of contents changes
from time to time. Instead of making calls across the network to the SQL Server (even
cached data on SQL Server requires a few calls back and forth), you could use the
caching example above.

There are two ways primary ways of handling this:


1. Setup a scheduled task on the SQL Server 2000 to output your table as XML to a
specified location on your web server. Because SQL Server 2000 can serialize
your data to DiffGrams used in DataSet construction, this is an easy way to
deliver updates to your DiffGram file described above in our caching example.
You could even setup a trigger on your SQL Server to generate a new DiffGram
when the contents of your table change, but that is beyond the scope of this
tutorial.
2. Another way is to adapt the example above to create not only a DataSet, but to
use classes from System.Data.OleDb or System.Data.SqlClient to get your data
from time to time from the server. In this particular case (which we'll do below),
creating a cache dependency wouldn't make much since because the SQL Server
is no longer updating your DiffGram file, identified by the private member
_filename in the example above.

You could adapt second method above to something like the following:
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data"
%>
<%@ Import Namespace="System.Data.SqlClient" %>
<script runat="server">
// If used frequently, store these strings in your Web.config
// and use ConfigurationSettings.AppSettings["key"] to get them out.
// If you do this, make sure these are constant strings!
private const string connstr = "Data Source=sqlserver1;Initial
Catalog=Web";
private const string cmdstr = "SELECT Title,URL FROM TOC";

private void Page_Load(Object src, EventArgs args) {


DataSet ds = (DataSet)Cache["mydata"];
if (ds == null) {
// Connect to the SQL Server and get our data using a DataAdapter
SqlConnection conn = new SQlConnection(connstr);
SqlCommand cmd = new SqlCommand(cmdstr, conn);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);

// Create a new DataTable and fill it


DataTable dt = new DataTable("Item");
adapter.Fill(dt);

// Now add our DataTable to a DataSet instance and add to cache


ds = new DataSet("TOC");
ds.Tables.Add(dt);
Cache.Insert("mydata", ds, null, DataTime.Now.AddHours(1),
NoSlidingExpiration);
}

// Bind our data


myRepeater.DataSource = ds;
myRepeater.DataBind();
}
Yes, I've chanced our ASP.NET control to a Repeater because a DataGrid wouldn't make
a lot of sense. I will describe what you could use in this example for a Repeater control in
a minute.

Describing the example above, it is really nothing more than what we had before execpt
that we have no CacheDependency because we have no files to watch, and we create our
DataSet from a DataTable that is filled by a SqlDataAdapter (or OleDbDataAdapter if
you prefer). DataSets are good to store in the Cache since they are easy to use, can be
used in any data-driven control, and can be serialized at will with one call to ReadXml()
or WriteXml().

Note: another thing to mention to those that have used System.Data.OleDb classes but
not System.Data.SqlClient classes, you will notice I didn't specify a Provider in the
connection string. This is because the SqlClient classes are only interested in SQL Server
connections and, hence, already know what the Provider is.

Finally, our Repeater control would look something like the following:
<body>
<asp:Repeater id="myRepeater" runat="server" Visible="true">
<ItemTemplate>
<dd><a href="<%# DataBinder.Eval(Container, "Item.URL") %>"><%#
DataBinder.Eval(Container, "Item.Title") %></a></dd>
</ItemTemplate>
</asp:Repeater>
</body>

The expressions above evaluate your Container (your DataSet object) and find the
"Item.Title" and "Item.URL". "Item" is the name of the data item, which is the the name
of the table usually. You may remember that we called our DataTable "Item" above:
DataTable dt = new DataTable("Item");

"Title" and "URL" our the names of our fields in the table. See, even your data is
appropriately named!

Conclusions

That pretty much wraps up the tutorial of how to use caching. There are many other
examples and scenarios of how to use Caching and DataSets to cache data, but this
tutorial is long enough I think. Please keep in mind that you can cache other objects as
well, not just DataSets. I find that caching DataSets where you used infrequently
accessed data is especially helpful, however, to decrease loads on your Web server, SQL
Server (or other database server), and network.
I hope you've found this tutorial helpful and that the wheels in your head are spinning
like mad with new ways to use caching to improve your web site's performance!

||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Introduction
ASP.NET has built-in cache engine that is used by ASP.NET pages to store and retrieve
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.

Placing an item in the cache is done in following way:

Cache ("key") = Value

Retrieving the data is just as simple

Value = Cache("key")
If Value <> Null Then
DisplayData(Value)
End If

For sophisticated functionality in Applications on 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.

• Expiration allows programmers to give cache items lifetimes, which can be


explicit (for example, expire at 12:00) or can be relative to an item's last use (for
example, expire 10 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.

Data Caching example


Collapse
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>

<html>
<script language="VB" runat="server">

Sub Page_Load(Src As Object, E As EventArgs)

Dim dataSource As DataView

' Retrieve item from cache if anything is not there then we


have to

' add to the cache

dataSource = Cache("CheDataSet")

If dataSource Is Nothing

Dim Conn As SqlConnection


Dim Cmd As SqlDataAdapter

Conn = New SqlConnection(_


"server=database;uid=sa;pwd=;database=Northw
ind")
Cmd = New SqlDataAdapter("select * from customers", Conn)

Dim ds As New DataSet


Cmd.Fill(ds, "dsUsers")

dataSource = New DataView(ds.Tables("dsUsers"))


Cache("CheDataSet") = dataSource

CacheMsg.Text = "Dataset was Created directly from the


Datebase. " &_
"Here the Cache was not used but the Cache
was " &_
"Created, so check for the performance next
time."
Else

cacheMsg.Text = "Dataset was Retrieved from cache which was


" &_
"created earlier."
End If

MyDataGrid.DataSource=dataSource
MyDataGrid.DataBind()
End Sub

</script>

<body>

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


<h3><font face="Verdana">Caching Data Example</font></h3>
<i><asp:label id="CacheMsg" runat="server"/></i>

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


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

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

Examples
1. When Executed for the first time

2. When Executed after the cache is created.


Conclusion
1. Data Caching should be used very carefully only when required.
2. Data caching allows objects to be cached programmatically.
3. The cache is scoped to an application and its lifetime is equivalent to the lifetime
of the application.

||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

In this article, you will learn about concepts, advantages, types of caching and about
implementation of caching in ASP.NET applications. The code also serves as an
example of using inline coding, creating user controls, trace mechanism, etc.

What is Caching?

Caching is a technique of persisting the data in memory for immediate access to


requesting program calls. Many in the developer community consider caching as one
of the features available to improve performance of Web applications.

Why Caching?

Consider a page that has list of Employee name, contact numbers and mail-Ids of
existing employees of a company on an intranet accessible by all employees. This is
very useful information that is available throughout the company and could also be
one of the most accessed pages. The functionality of adding, updating or deleting is
usually less intensive compared to more transaction-based systems like Purchase
ordering, Voucher creation etc. Now in a normal scenario the process of querying
database for each request is not cost-effective in terms of server resources, hence is
lot better to cache or persist the data to avoid this costly loss of resources.

The .NET Advantage

ASP.NET provides the flexibility in terms of caching at different levels.

1. Page Level Output Caching

This is at the page level and one of the easiest means for caching pages. This
requires one to specify Duration of cache and Attribute of caching.

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

The above syntax specifies that the page be cached for duration of 60 seconds and
the value "none" for VaryByParam* attribute makes sure that there is a single
cached page available for this duration specified.

* VaryByParam can take various "key" parameter names in query string. Also there
are other attributes like VaryByHeader, VaryByCustom etc. Please refer to MSDN for
more on this.

2. Fragment Caching

Even though this definition refers to caching portion/s of page, it is actually caching a
user control that can be used in a base web form page. In theory, if you have used
include files in the traditional ASP model then this caching model is like caching these
include files separately. In ASP.NET more often this is done through User Controls.
Initially even though one feels a bit misleading, this is a significant technique that
can be used especially when implementing "n" instances of the controls in various
*.aspx pages. We can use the same syntax that we declared for the page level
caching as shown above, but the power of fragment caching comes from the
attribute "VaryByControl". Using this attribute one can cache a user control based on
the properties exposed.

Syntax: <%@ OutputCache Duration="60" VaryByControl="DepartmentId" %>

The above syntax when declared within an *.ascx file ensures that the control is
cached for 60 seconds and the number of representations of cached control is
dependant on the property "DepartmentId" declared in the control.

Add the following into an *.ascx file. Please note the use of tag "Control" and the
cache declaration.

<%@ Control Language="C#"%>


<%@ outputcache duration="60" varybycontrol="DepartMentId" %>
<script runat="server">
private int _Departmentid=0;
public int DepartMentId
{
get{return _Departmentid;}
set{_Departmentid =value;}
}
//Load event of control
void Page_Load(Object sender, EventArgs e)
{
lblText.Text = "Time is " + DateTime.Now.ToString() + " for Department id = "
+ _Departmentid + "\n";
}
</script>
<asp:Label id="lblText" runat="server"></asp:Label>

Add the following to an *.aspx file. Please note the way "Register" tag is used; the
declaration of control using syntax <[TagPrefix]:[TagName]>; Usage of property "
DepartMentId". Open the page in two browsers and closely watch the Base form
timing and the User control timing. Also note that the following page results in two
copies or representation of user control in the cache.

<%@ Page Language="C#" Trace="true" %>


<%@ Register TagPrefix="CacheSample" TagName="Text"
Src="CachingControl.ascx" %>
<script runat=server>
void Page_Load(Object sender, EventArgs e)
{
this.lbltime.Text ="Base form time is " + DateTime.Now.ToString() + "\n";
}
</script>
<html>
<head>
</head>
<body>
<form runat="server" ID="Form2">
<table>
<tbody>
<tr>
<td>
<asp:Label id="lbltime" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<CACHESAMPLE:TEXT id="instance1" runat="Server" DepartMentId="0">
</CACHESAMPLE:TEXT>
</td>
</tr>
<tr>
<td>
<CACHESAMPLE:TEXT id="instance2" runat="Server" DepartMentId="1">
</CACHESAMPLE:TEXT>
</td>
</tr>
</tbody>
</table>
</form>
</body>
</html>

3. Application Level Caching

With Page level Output caching one cannot cache objects between pages within an
application. Fragment caching is great in that sense but has limitations by using user
controls as means to do. We can use the Cache object programmatically to take
advantage of caching objects and share the same between pages. Further the
availability of different overloaded methods gives a greater flexibility for our Cache
policy like Timespan, Absolute expiration etc. But one of the biggest takes is the
CacheDependancy. This means that one can create a cache and associate with it a
dependency that is either another cache key or a file.

In almost all Web applications there could be numerous master tables that act as
lookups to application specific tables. For e.g. if you take up adding a Employee,
usually one has master tables like "tblQualification" to get list of qualifications,
"tblLocations" to get list of locations etc. These tables* are usually set during the
initial application configuration phase and could be modified once a month or even
less than that. Hence it makes sense for us to use them in our Cache rather than
making calls to database on each request. But then what Cache Policy do we adopt?

We cannot hold these objects in Cache for entire application instance, because if
anybody changes data in these tables one has to also refresh the cache. It is here
that CacheDependancy can be used.

* Even though these tables are less frequently used for updates, they are extensively
used in our select statements through out the applications.

Find below the snippet that uses CacheDependancy. Here what I have done is to
provide a list view of existing employees. You need to create a Database in Sql
Server, setup some data before you can continue. The schema scripts are enclosed in
the article.

Add database connection value in Web.Config and change the value as per your
setup.

<appSettings>
<add key="conn" value="Data Source=vishnu;trusted_connection=yes;Initial
Catalog=Users"/>
</appSettings>

First I get the dataset into which I fill the user list. But before this I check for the
cache initially if it exists I directly cast it to a dataset, if not create a cache again.
daUsers.Fill(dsUsers,"tblUsers");

I create the cache with "Users" as key using Cache.Insert* and link this with a file
"Master.xml". This "Master.xml" is a XML file that contains Master data of
"tblQualifications" and "tbllocations". I have used "Server.MapPath" to get the
physical path of the file on the server. The CacheDependancy instance will make sure
that any change in this dependency file means that you need to recreate your cache
key definition. This is a great feature to use since I can recreate my cache only when
required instead of caching the data at the page level.

Cache.Insert("Users",dsUsers,new
System.Web.Caching.CacheDependency(Server.MapPath("Master.xml")) ,
DateTime.Now.AddSeconds(45),TimeSpan.Zero);

* For other overloaded parameters refer MSDN.

Also note how we could use trace within to add my own statements.

HttpContext.Current.Trace.Write("from Database..");

<%@ Page Language="c#" Trace="true" %>


<%@ import Namespace="System" %>
<%@ import Namespace="System.Data" %>
<%@ import Namespace="System.Data.SqlClient" %>
<%@ import Namespace="System.Configuration" %>
<%@ import Namespace="System.Web" %>
<%@ import Namespace="System.Collections" %>
<%@ import Namespace="System.IO" %>
<script runat="server">
void Page_Load(Object sender, EventArgs e)
{
DataSet dsUsers;
try
{
if(Cache["Users"]==null)
{
SqlConnection cn;
dsUsers = new DataSet("new");
cn = new SqlConnection(ConfigurationSettings.AppSettings.Get("conn"));
SqlDataAdapter daUsers;
daUsers = new SqlDataAdapter("Select * from tblUsers",cn);
cn.Open();
daUsers.Fill(dsUsers,"tblUsers");
//Update the cache object
Cache.Insert("Users",dsUsers, new System.Web.Caching.CacheDependency(
Server.MapPath("Master.xml")), DateTime.Now.AddSeconds(45),TimeSpan.Zero);
HttpContext.Current.Trace.Write(DateTime.Now.AddSeconds(45).ToString() + "
is expiry time..");
cn.Close();
cn.Dispose();
HttpContext.Current.Trace.Write("from Database..");
lblChange.Text ="From the database....";
}
else
{
HttpContext.Current.Trace.Write("From cache..");
lblChange.Text ="From the cache....";
dsUsers= (DataSet) Cache["Users"];
}
dlUsers.DataSource =dsUsers;
dlUsers.DataMember = dsUsers.Tables[0].TableName ;
//lblChange.Text += Server.MapPath("Master.xml");
this.DataBind();
}
catch(Exception ex)
{
lblChange.Text = ex.Message;
}
}
</script>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
<title>Cache Dependency Tester</title>
<meta content="Microsoft Visual Studio 7.0" name="GENERATOR" />
<meta content="C#" name="CODE_LANGUAGE" />
<meta content="JavaScript" name="vs_defaultClientScript" />
<meta content="http://schemas.microsoft.com/intellisense/ie5"
name="vs_targetSchema" />
</head>
<body ms_positioning="GridLayout">
<form id="Form1" method="post" runat="server">
<asp:DataList id="dlUsers" style="Z-INDEX: 101; LEFT: 44px; POSITION: absolute;
TOP: 104px" runat="server" Height="148px" Width="343px" BorderWidth="1px"
GridLines="Horizontal" CellPadding="4" BackColor="White" ForeColor="Black"
BorderStyle="None" BorderColor="#CCCCCC">
<SelectedItemStyle font-bold="True" forecolor="White"
backcolor="#CC3333"></SelectedItemStyle>
<FooterStyle forecolor="Black" backcolor="#CCCC99"></FooterStyle>
<HeaderStyle font-bold="True" forecolor="White"
backcolor="#333333"></HeaderStyle>
<ItemTemplate>
<table>
<tr>
<td>
<%#DataBinder.Eval(Container.DataItem,"UserId")%></td>
<td>
<%#DataBinder.Eval(Container.DataItem,"FirstName")%></td>
<td>
<%#DataBinder.Eval(Container.DataItem,"LastName")%></td>
</tr>
</table>
</ItemTemplate>
</asp:DataList>
<asp:Label id="lblChange" style="Z-INDEX: 102; LEFT: 46px; POSITION: absolute;
TOP: 63px" runat="server" Height="28px" Width="295px"></asp:Label>
<asp:Button id="btnMaster" style="Z-INDEX: 103; LEFT: 50px; POSITION:
absolute; TOP: 293px" onclick="btnMaster_Click" runat="server" Text="Refresh
Master"></asp:Button>
</form>
</body>
</html>
We created the page that initiates and uses the Cache. For testing purpose we need
another page that will overwrite this "Master.xml" on click of a button for which the
code snippet is as follows. This ideally should be our master maintenance page that
adds/updates Master records in database and overwrites the XML. But to make it
easy I have just written an overwriting sample.

<%@ Page Language="C#" Trace="true"%>


<%@ import Namespace="System" %>
<%@ import Namespace="System.Data" %>
<%@ import Namespace="System.Data.SqlClient" %>
<script runat="server">
void btnMaster_Click(Object sender, EventArgs e)
{
//Call save function
this.Save();
}
void Save()
{
try
{
SqlConnection cn;
DataSet dsUsers = new DataSet("Users");
//I have used this to get the Connectionstring from the
//Configuration file.
cn = new SqlConnection(ConfigurationSettings.AppSettings.Get("conn"));
SqlDataAdapter daQualification;
SqlDataAdapter daLocations;
daQualification = new SqlDataAdapter("Select * from tblqualifications",cn);
daLocations = new SqlDataAdapter("Select * from tblLocations",cn);
cn.Open();
daQualification.Fill(dsUsers,"tblqualifications");
daLocations.Fill(dsUsers,"tblLocations");
HttpContext.Current.Trace.Write("Masters data up..");
//Overwrite the XML file. Also please read MSDN on the overloaded parameters for
WriteXml
dsUsers.WriteXml(HttpContext.Current.Server.MapPath
"Master.xml"),XmlWriteMode.WriteSchema);
cn.Close();
cn.Dispose();
}
catch(Exception ex)
{
throw new Exception(ex.Message);
}
}
</script>
<html>
<head>
</head>
<body>
<form runat="server" ID="Form1">
<span>
<table>
<tbody>
<tr>
<td>
<label id="lblRefresh" runat="server">
Rewrite the XML File by clicking the buttonbelow.</label>
</td>
</tr>
<tr align="middle">
<td>
<asp:Button id="btnMaster" onclick="btnMaster_Click" runat="server"
Text="Write XML"></asp:Button>
</td>
</tr>
</tbody>
</table>
</span>
</form>
</body>
</html>

Now once you have created the above pages i.e. one that implements caching and
other that overwrites the dependency file, create two instance of browser and open
the cache implementation page and note for trace, label text; open the other
instance of browser with the page which overwrites the XML. Note the former, the
first time it fetches data from the database and the subsequent request will be from
cache till your expiration time of 45 seconds is reached or anyone overwrites or
changes the "Master.xml" file. Also give a look on Timespan parameter since you
have a concept of Sliding expiration that can also be implemented. Keep refreshing
the first page and you will see that trace indicates the cached page retrieval. Click
the overwrite XML button on the latter page that would overwrite the XML and again
refresh the former page to note that the data is retrieved from database. Though in
this example I have not shown any direct relation between the cached data and the
dependency file (like get values from dependency file and merge with cached object
etc) in terms of integrated usage, this could very easily be designed and
implemented. Dependency caching is a powerful technique that .NET supports and
should be utilized wherever applicable.

Conclusion

Caching is a technique that definitely improves the performance of web applications


if one is careful to have a balance in terms of which data needs to be cached and
parameter values for expiration policy.

You might also like