Performance with page cache in ASP.NET

Santosh4u
Posted by in ASP.NET category on for Beginner level | Views : 7690 red flag

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.
Introduction

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 feature.


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.



Page Output Cache


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 every request.


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.





Creating a Web project as an example

In Listing 1, we have the ASPX file code for cache usage.

 

Listing 1. Displaying the date and time when the page was loaded

...

<body>

    <form id="form1" runat="server">

<div>

  <% Response.Write(System.DateTime.Now); %>

</div>

   </form>

</body>

</html>


Run the 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.



Listing 2. 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.


Run SQL 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.

 


Figure 2.

Events for SQL Profiler monitoring

Listing 3. Configuration of the web.config with a new Northwind connection

...

<configuration>

<appSettings/>

<connectionStrings>

  <add name="Northwind"

    connectionString=" Data Source=MyHost;

      Initial Catalog=Northwind;

      Integrated Security=True;User ID=sa;

      Password=MySaPassword "

      providerName="System.Data.SqlClient"/>

 </connectionStrings>   

<system.web

...

 

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 data.

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).

Listing 4. Configuration of the page for data display

...

<div>

<% Response.Write(System.DateTime.Now); %>

<asp:SqlDataSource ID="NorthwindSource"

runat="server"

SelectCommand=

  "SELECT CustomerID, CompanyName,

  ContactName FROM Customers"

ConnectionString="<%$ConnectionStrings:Northwind %>"/>

<asp:DataGrid ID="dgNorthwind"

runat="server"

DataSourceID="NorthwindSource" />

</div>


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.


Making 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).



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.

 

Listing 5. CacheControl code created to represent the partial cache.


<%@ Control Language="C#" AutoEventWireup="true"

  CodeFile="CacheControl.ascx.cs"

  Inherits="CacheControl" %>

<%@ 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 environment.

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

 

Listing 6. Main page code adding the CacheControl that we have created


<%@ Page Language="C#" AutoEventWireup="true" 

  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<%@ Register Src="CacheControl.ascx"

  TagName="CacheControl" TagPrefix="uc1" %>

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

<div>

<% Response.Write(System.DateTime.Now); %>

<uc1:CacheControl ID="CacheControl1" runat="server" />

    <br />

<asp:SqlDataSource ID="NorthwindSource"

runat="server"

SelectCommand=

  "SELECT CustomerID, CompanyName, ContactName FROM Customers" ConnectionString="<%$ConnectionStrings:Northwind %>" />

<asp:DataGrid ID="dgNorthwind"

runat="server"

DataSourceID="NorthwindSource" />

</div>

</form>

</body>

</html>

 

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 OutputCache directive.


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.


Notifying the 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.

 

Listing 7. Enabling cache notification for a table in the database

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>

  aspnet_regsql -S MyHost -U sa

  -d Northwind -ed -et -t Customers

Password:

Enabling the database for SQL cache dependency.

Finished.

Enabling the table for SQL cache dependency.

Finished.

Listing 8. Enabling in the web.config the facility of SqlDependency

...

<caching>

<sqlCacheDependency

  enabled="true">

<databases>

  <add name="NWDependency"

   connectionStringName="Northwind"

   pollTime="2000"/>

</databases>

</sqlCacheDependency>

</caching>

...


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:


Listing 9. Associating a Cache with SqlDependency to the ASPX page

...

<%@ OutputCache Duration="60"

  SqlDependency="NWDependency:Customers"

  VaryByParam="*" %>

...

 

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

...

<font color=navy>

  <asp:Substitution runat="server" ID="Substitution1"

    MethodName="MySubstitutionMethod" /><br /><br />

</font>

...

Listing 11. Function called by the Substitution Control


public partial class _Default : System.Web.UI.Page

{

    protected void Page_Load(object sender,

      EventArgs e)

    {

 

    }

    public static string MySubstitutionMethod(

      HttpContext currentContext)

    {

        return DateTime.Now.ToString();

    }

}


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 20 seconds.


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.

Conclusion
There 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 page-to-page.
Page copy protected against web site content infringement by Copyscape

About the Author

Santosh4u
Full Name: dotnetexp behera
Member Level: Bronze
Member Status: Member
Member Since: 10/7/2009 12:27:26 PM
Country: Malaysia

http://santoshdotnetarena.blogspot.com/

Login to vote for this post.

Comments or Responses

Login to post response

Comment using Facebook(Author doesn't get notification)