I am writing this article to check how the cache of a page works in a website. I shall show all the details with example.
Normally, when we develop an
application, something that concerns us greatly is performance; and few things
provide more immediate benefits in terms of performance than the caching
However, what is caching
after all? Caching is the name given to the process of storing, in a
quick access location, data that is accessed frequently, liberating the system
(application, database or OS) from generating them again when requested. Often,
this location is memory, which is much more efficient and less expensive than
other resources such as hard disk or databases.
ASP.NET counts on two specific features for caching: the cache API
(which will not be broached in this article), for storage of arbitrary data,
such as information from a database or information from a file in a disk, and
the page’s Cache, used to store Web pages.
Let us imagine the following
scenario: you are developing a Web application with a customers’ list and in
this list the nature of the address comes from a table of the database (street,
road, avenue, square etc.). Since this data is, basically, always the same, why
search for it in the database every time the page is requested, consuming network resources (to access the database),
from the database (to process the request) and
from the Web Server (which shall display the new list that the database
returned)? With the caching feature, you can leave this list, or even
the customers’ page, stored static in memory and it will simply be displayed
every time it is requested.
A page can be put in cache in one of
two ways: total or partially. When we deal with total page cache, we understand
that the whole page, plus its content, will be recorded static in the memory,
and it is this information that will be displayed to the final user when the
page is requested.
In the case of partial page cache,
we can understand that we will only store a fragment of the page in memory,
while the rest of that same page will continue to be rebuilt dynamically at
To demonstrate the running behavior
of the total page cache, we will create a Web project called “Demo” (as shows Figure
1) and we will command the page to print the current time value.
a Web project as an example
In Listing 1, we have the
ASPX file code for cache usage.
Displaying the date and time when the page was loaded
<form id="form1" runat="server">
application and update it several times in some instants. You will manage to
check that the time printed is the current date and time of when the page was
effectively loaded, which means that it was processed and rebuilt again.
A page cache can be made
in any gadget that supports the cache easiness, such as the Web server, proxy
server or the browser, which requested the page itself. In order to enable page
cache, a new page directive must be added called OutputCache (as shows Listing
2), and the Duration attribute must obligatorily be defined with the
amount of seconds during which this page will remain in cache.
Using the OutputCache directive
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ OutputCache Duration="20" VaryByParam="*" %>
It is common to define other attributes, which establish priorities for the
cache variation. In the example of Listing 2, I use the attribute VaryByParam
with the value “*”, indicating that any parameter variation so much for Get
(QueryString), as for Post, will make it so that the server
rebuilds the page and does not use the version stored in cache.
We define the Duration
attribute to 20 seconds and let us see again how the page behaves running (do not forget to save the changes made) and updating it several
times until the defined 20 seconds are exceeded. Check that the printed time
is modified only when the 20 seconds expire, which demonstrates that the page
was not reprocessed during this time.
Confirming the page cache
Now that we already know
how to make a page cache, let us see the page’s behavior when we have data to
be displayed. And to confirm if the page will be rebuilt or not we will use a
connection with the database and see, in the database, the requested executions.
For this, we will use SQL Profiler tool that comes with SQL Server.
Profiler and select the File>New>Trace option. A window will
ask for the credentials to access the database, provide them and a new window
will appear asking for a name for the new trace. Name it “CachingSampleTrace”.
Go to the Events
tab and remove all the events attributed to tracing as default, with the
exception of TSQL>SQL:BatchCompleted. This event will list the
commands completed in your SQL Server. The configuration of events shall be as
shows Figure 2.
SQL Profiler monitoring
Configuration of the web.config with a new Northwind connection
Integrated Security=True;User ID=sa;
It is worth remembering
that the good security practices demand that we never leave passwords without
cryptography anywhere. But our focus today is to demonstrate one other
functionality. After the connection configuration, we will return to the
ASP.NET page and we will create a new data source, and an object to display the
In the example, I set up
a SqlDataSource using the connection we created and a DataGrid
that uses this DataSource, as shown in Listing 4 (ASPX file).
Configuration of the page for data display
"SELECT CustomerID, CompanyName,
ContactName FROM Customers"
Before running the page,
return to the open SQL Profiler and clear all the events that appear (Ctrl +
Shift + Del). Run the page. It will display the data from the SqlDataSource
in the DataGrid and the SqlProfiler will display the execution of
an SQL call in the database.
Update the page several
times during 20 seconds and return to examining the SQL Profiler. Notice how
many calls in the database were made. Only one call is made for every 20
seconds of update.
This example shows how
to save time in simple lists, static, that change with little or no frequency
in the life of the application. However, if you edit any record in the database
and return to the page you will verify that, since the page is not reprocessed
until the cache time expires, it will not show the update performed.
This means that we
cannot make the cache of information that changes more frequently? No, this
means that if we do the caching of information that change more
frequently we run the risk of displaying, to our user, outdated information,
therefore, this is not recommended for those who work with databases other than
the SQL Server, such as DB2, Informix etc.
For those who work with
SQL Server, however, Microsoft disposes a pretty interesting easiness, allowing
the data that is in cache to be updated even before the defined time expires.
We will discuss this further in the article.
partial Caching of the page
In the previous example
we could verify how to make cache in an entire page. Now we will see how to do
this for only a section of the page. First we will have to create a WebUserControl,
in such a manner that you can reuse it in one or more pages.
Right-click over the
project and select the Add New Item option, select the Web User
Control option and name this new control “CacheControl”
Figure 3. Creating a Web User Control
Visual Studio will create an object
very similar to a Web page; however, it is a WebUserControl. Place in
this control a code line that shows the current hour of the system in the page
(as we have done previously in our ASPX page) and add a 5 seconds cache for it,
adding an OutputCache directive at the top of the control with a value
of 5 seconds to the Duration attribute. See in Listing 5, what
the final code of User Control will be like.
5. CacheControl code created to
represent the partial cache.
Control Language="C#" AutoEventWireup="true"
OutputCache Duration="5" VaryByParam="*" %>
<b><% Response.Write( System.DateTime.Now); %></b>
Now remove the OutputCache
that we have placed in our main page. This will prevent that its cache (with a
longer duration) hides the cache of our control. Again open the main page in
design mode and drag the control that we have created to the design
This will automatically add the
necessary tags to render the control when the page is composed. The main
page’s code will be similar to the one presented in
6. Main page code adding the
CacheControl that we have created
<%@ Page Language="C#"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Src="CacheControl.ascx"
TagName="CacheControl" TagPrefix="uc1" %>
<uc1:CacheControl ID="CacheControl1" runat="server"
"SELECT CustomerID, CompanyName, ContactName FROM Customers" ConnectionString="<%$ConnectionStrings:Northwind
Save and run the page. Update it
several times for about 10 seconds and observe how one of the times that we
place shows the seconds as they pass, and the other (in boldface) only updates
every 5 seconds. The time in boldface is the time of our control, and its
update frequency comes from the Duration parameter that we placed in the
In case that you wish to confirm the
partial caching of the page, repeat the creation process of the Web
User Control creating a “CacheControl2”. Repeat the process done with our CacheControl,
but placing a cache time of 8 seconds. Drag it to the main page and see the
behavior of the content after the updates.
As you can notice, the partial cache
of information can bring the static controls benefit without damaging a page
with contents that should be dynamic.
page when a table is updated
As has been said previously, it is
possible to notify a web page when the content of a table is modified. The name
given to this is SqlDependency and to enable it, two steps must be
followed. The first one is to enable the SqlDependency in the database.
For this, a utility that comes with .NET 2.0,
called aspnet_regsql, must be executed, specifying the database and the
table that we want to notify the IIS in case of alteration.
Listing 7 shows the complete command for our example (we must use the
command prompt to execute the code), plus the return message when successfully executed.
7. Enabling cache notification for a
table in the database
aspnet_regsql -S MyHost -U sa
Northwind -ed -et -t Customers
database for SQL cache dependency.
table for SQL cache dependency.
Listing 8. Enabling in the
web.config the facility of SqlDependency
We need to attach a connection to
our dependency, which, in our case, is Northwind; we name our dependency
(NWDependency) and we attribute a pollTime, which is the time in
which the cache will be read, in milliseconds, from the SQL server.
We now need to see to it that our
page behaves differently when we make an alteration in the Customers’
table. For this, once again add the OutputCache directive to the main page with the duration of 60
seconds, and add the SqlDependency parameter specifying the dependency
that we created in the web.config and the table that we wish to observe, as shown in the code to follow:
Associating a Cache with SqlDependency to the ASPX page
<%@ OutputCache Duration="60"
If you run the application, you will
notice that the data will be outdated for 60 seconds, but before this time
expires, update any record in your SQL Server database (via Query Analyzer
or straight from the Visual Studio) and once again update the web page web that
is running. Notice that the data that you updated in the SQL Server was
updated, even if the cache time has not reached the 60 seconds.
If you have kept the SQL Profile
open, take a look at the commands that are being executed against your
database. Notice that an access to the database is made every two seconds,
which is exactly the time that we have configured in the pollTime
attribute of our cache database.
Listing 10. Substitution
Control in the ASPX
/><br /><br />
Listing 11. Function called by
the Substitution Control
partial class _Default :
public static string MySubstitutionMethod(
To test, run the page and update it
at every second. Observe that the text printed by the Substitution control
(in blue) is updated every second, even if we have the page’s cache defined for
It is worth mentioning that the Substitution
control cannot be placed in User Contro,s or Master Pages
that already have the OutputCache directive added to them.
ConclusionThere are several ways to improve
performance, using caching in ASP.NET 2.0 and to provide the cache
easiness only for the parts of the page where this feature
will bring us benefits. The important is to define where the caching
will be more profitable, from application to application, and from times of