Home
    Shop
    Advertise
    Write For Us
    Affiliate
    Newsletter
    Contact

Caching Techniques in ASP.NET 2.0

Performance is the key requirement of any application. One of important technique which helps in the performance of application is Caching. Caching is the process of storing frequently used data on the server to fulfill subsequent requests.

 

Reusing pages from memory is much faster than re-creating pages every time they are requesting. Caching increases your application's performance, scalability and availability. In ASP.NET, caching is implemented as an HttpModule that listens to all HttpRequests that come through the ASP.NET worker process.

We will discuss various caching techniques including the new SQL Invalidation caching capabilities and Post-cache substitution feature. We will throw some light on custom cache dependencies.

Methods of Caching

We can deal with caching in several ways. Different caching methods are given below:

  • Output Caching

  • Partial Page Caching

  • Data Caching

Output Caching

Output Caching is a way to keep the dynamically generated page content in the server's memory to fulfill future requests. You apply output caching by inserting an OutputCache page directive at the top of an .aspx page as shown below.

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

The Duration attribute defines the number of seconds a page is stored in memory.

Attributes of Output Caching

The VaryByParam attribute determines which versions of the page output are actually cached. You can generate different responses based on whether an HTTP-POST or HTTP-GET response is required. You can also cache different responses based on different attributes like VaryByHeader, VaryByCustom, VaryByControl.

The VaryByParam attribute can specify which QueryString parameters cause a new version of the page to be cached.

<%@ OutputCache Duration="60" VaryByParam = "ProductID;CategoryID"  %>

For example, if you have a page called products.aspx that includes products and category information in the QueryString such as productID and CategoryID. The page directive, shown above caches the products page for every different value of CategoryID and ProductID. This way the number of pages cached can be calculated using below simple equation

Cached Items = (number of categories) * (number of products)

Cached Items is the number of pages that would be stored in cache.

If you want to cache a new version of the page based on any combination of parameters, you can use VaryByParam ="*", as shown below

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

VaryByControl

VaryByControl can be easy way to get good performance from complex user controls that render a lot of HTML that doesn't change often. For example, imagine a User Control that renders a Combo Box showing the names of all the countries in the world. Certainly, the names of countries don't change that often. So you can set cache based on this user Control where duration attribute can be set to say one fortnight.

<%@ OutputCache Duration="1296000" VaryByControl="drpdownCountries"  %>

VaryByCustom

Although the VaryBy Attribute offer a great deal of flexibility, but you need more flexibility. If you want to take the OutputCache directive from products page and cache a value stored in a cookie, you can add VaryByCustom. The value of VaryByCustom is passed into the GetVaryByCustomString method that can be added to the Global.asax file. This method is called every time the page is requested, and it is the function's responsibility to return a value. A different version of the page is cached for each unique values returned. For example, say your users have a cookie called colors that has three potential values: blue, yellow and green. You want to allow users to specify their preferred color. Therefore, the OutputCache directive using the first example caches many versions of the page as given below in the equation:

Cached Items = (num of categoryID's) * (num of productID's) * ( 3 possible colors)

To sum up, suppose there were ten potential values for CategoryID, four potential ProductID for each CategoryID and three possible color values. This adds up to 120 different potential cached versions of this single product page.

Caching is tradeoff between CPU and memory. Every page request served from the cache saves a round trip to database. Efficient use of caching can translate into significant cost savings.

Partial Page Caching

Partial Page Caching enables you to cache only specific parts of a web page. Partial page caching is achieved with the caching of user controls. You can build your ASP.NET pages utilizing numerous user controls and then apply output caching to the user controls. This in essence, caches only the parts of the page that you need.

Shared Attribute

Usually, user controls are reused on multiple pages in the application. However, when these UserControls are cached with the OutputCache directive's default attributes, they are cached on a per-page basis. So there is a chance that same user control might be cached twice. By setting Shared attribute to true, we can share user control's output among multiple pages.

<%@ OutputCache Duration="1296000" VaryByParam="*" Shared="true" %>

Post-Cache Substitution

Output Caching enables you to cache entire page. However often you want the benefits of output caching, but you also wants to add a small bit of dynamic content on the page. ASP.NET 2.0 introduced Post-Cache substitution as an oppurtunity to make changes to about-to-be-rendered page. How it works? A control is added to page that acts as a place holder. It calls a method that you specify after the cached content has been returned. This method returns any string output.

There are two ways you can control the Post-cache substitution:

  • Call the new Response.WriteSubstitution method, passing it a reference to the desired substitution method callback.

  • Add a <asp:Substitution>control to the page at the desired location and set its methodName attribute to the name of callback method.

Let's see this with an example. Create a website with a Default.aspx. Drag a label control and a substitution contorl to the design surface. The code in below given listing updates the label to display the current time, but the page is cached immediately and future requests return that cached value. Set the methodName property in the substitution control to GetCorrectTime, meaning the name of the static method that is called after the page is retrieved from the cache.

The callback method must be static because the page that is rendered doesn't really exist at this point. Because you don't have a page instance to work with, this method is limited in its scope. However, the current HttpContext is passed into the method, so you have access to the Session, Request and Response object.


Toolbox

<%@ OutputCache Duration="90" VaryByParam="None"  %>
 
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>PostCacheSubstitution example</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <h2>Post Cache Substitution example</h2>
        <asp:Label ID="Label2" runat="server" Text="CachedTime"></asp:Label>
        <asp:Label ID="Label1" runat="server" Text="CachedTime"></asp:Label>
        <br />
        <h2>Dynamic content inserted into Cached page using Substitution control</h2>
        <asp:Substitution ID="Substitution1" runat="server" MethodName="GetCorrectTime" />
</body>
</html>       public partial class Default2 : System.Web.UI.Page
      {
            public static string GetCorrectTime(HttpContext context)
            {
                  return DateTime.Now.ToLongTimeString() + "from" + context.User.Identity.Name;
            }
 
            protected void Page_Load(object sender, EventArgs e)
            {
                  Label1.Text = DateTime.Now.ToLongTimeString();
            }
      }

The ASPX page listed above has a label and a Post-cache Substitution control. The control acts as a place holder where you want dynamic content injected after the page is returned from the cache. The very first time the page is visited only the label is updated because no cached content is returned. The second time the page is visited, however the entire page is retrieved from the cache- the page handler isn't called, consequently, none of the page-level events fire. However, the GetCorrectTime method is called after the cache module completes its work as shown above where dynamic user identity is displayed

Data Caching

Output Caching is done almost declaratively. But you can perform data caching programmatically. You can use cache object to start caching specific data items for later use on a particular page. The cache object enables you to store everything from simple name/value pairs to more complex objects like datasets and entire aspx pages.

You can use the cache object in the following fashion:

Cache["dataset"] = mydataset;

After an item is in cache, you can retrieve it later as shown below:

DataSet ds = new DataSet();
        ds = (DataSet)Cache["dataset"];

Using cache object is an outstanding way to cache your pages. Above fragment shows simple use of the Cache object.

Cache Dependencies

ASP.NET 2.0 now ships with the time-based, file-based and now SQL-based CacheDependency support. The real power of cache object comes with its capability to invalidate itself. Using the cache object, you can store and also invalidate items in the cache based on several different dependencies

  • File based dependencies

  • Key based dependencies

  • Time based dependencies

  • SQL based dependencies

When inserting items into the cache object, you set the dependencies with the Insert method as shown below.

Cache.Insert("Conn",ConnectionStringsSection,new System.Web.Caching.CacheDependency(Server.MapPath("config.xml"))) ;

By using a dependency when the item being referenced changes, you remove the cache for that item from memory.

Another important feature in ASP.NET 2.0 is that you can create your own custom dependencies which are inherited from CacheDependency class. When you create your own cache dependencies, you have the option to add procedures to invalidate cache upon arrival of MSMQ message or create a Oracle database specific Cache dependency.

SQL Server based Cache dependency

This new feature allows invalidating cache when ever underlying data in the database changes. No stale data is stored in cache. To utilize the new SQL Server Cache dependency feature, you must perform a one-time setup of your SQL Server database. We have to use aspnet_regsql.exe tool to enable the database for this new invalidation feature as shown below: we need to pass following parameters to aspnet_regsql.exe as shown below:

aspnet_regsql.exe -S localhost -U sa -P sa -d Northwind -ed

From this command prompt, you can see that we simply enabled the Northwind database for SQL cache invalidation. The name of the SQL machine was passed in with –S, the username with –U, the database with –d, and most importantly, the command to enable SQL cache invalidation was –ed.

Now that you have enabled the database for SQL cache invalidation, you can enable one or more tables contained within the North wind database.

Enabling Tables

You enable one or more tables by using the following command.

aspnet_regsql.exe -S localhost -U sa -P sa -d Northwind -t Customers -et

You can see that this command is not much different from the one for enabling database, except for the extra –t customers entry and the use of –et to enable the table rather than –ed to enable a database. After the table is enabled, you can begin using the SQL Cache invalidation feature.

To configure your application to work with SQL Server cache invalidation, the first step is to make some changes to Web.config file. In the Web.config file, specify that you want to work with the north wind database and you want ASP.NET connected to it.

<connectionStrings>
  <add name="NorthwindConnectionString" connectionString="Data Source=ARAS02-XP;Initial Catalog=Northwind;User ID=sa;Password = sa;"
   providerName="System.Data.SqlClient" />
 </connectionStrings>
       <system.web>
    <caching>
      <sqlCacheDependency enabled ="true">
        <databases>
          <add name="Northwind" connectionStringName ="NorthwindConnectionstring" pollTime ="500"/>
        </databases >
      </sqlCacheDependency >
    </caching>
web.config file

From above listing, you can see that connection string information is utilized later in the configuration settings for SQL Server cache invalidation. The SQL Server cache invalidation is configured using the new <caching> element. This element must be nested within the <system.web> elements. Because you are working with SQL Server cache dependency, you must use a <sqlCacheDependency> child node. You enable the entire process by using the enabled=true attribute.

Now that the Web.config file is set and ready to go, create a page with label control, Gridview control and sql data source control as shown below.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2"  %>
<%@ OutputCache Duration="3600" VaryByParam="None" SqlDependency="Northwind:Customers" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Sql based Cache Dependency</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
     
        <asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1">
        </asp:GridView>
   
    </div>
        <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString1 %>"
            SelectCommand="SELECT * FROM [Alphabetical list of products]"></asp:SqlDataSource>
    </form>
</body>
</html>
protected void Page_Load(object sender, EventArgs e)
    {
        Label1.Text = "PAGE CREATED AT" & DateTime.Now.ToShortTimeString()
    }

You can observe in above HTML listing in the output cache directive, you can see the sqlDependency attribute. This enables a particular page to use SQL Server cache invalidation. The value of Northwind:Products specifies that you want the SQL Server cache invalidation enabled for the products table within Northwind database.

Cache will be disabled if the products table of the Northwind database has any changes made to the data that it contains which invalidates cache and a new cache is generated from the result. Below fig shows the output when the page ran for the first time.


Output listing

In above fig, for the productID 1, you can observe the productname as Chai1. For this entry, go to Sql Server and change the value of productname from chai1 to chai3. Before sql server cache invalidation, this change would have done nothing to output cache. This original page output in the cache would be still present and end user would still see the Chai1 as product name for the duration specified in the page's OutputCache directive. Because of SQL Server cache invalidation, after the underlying information is changed, the output cache is invalidated, a new resultset is retrieved, and the new result set is cached. When a change has been made, you see the results as shown below


Finally, ASP.NET 2.0 has refactored and unsealed CacheDependency class which allows creating custom cache dependencies. Another outstanding feature of ASP.NET 2.0 is SQL Server cache invalidation which enables you to invalidate items stored in cache when underlying changes occur to the data in the tables being covered. Post Cache Substitution fills in an important gap in ASP. Net's technology, enabling you to have both the best highly dynamic content and a high-performance web site with caching.


Tutorial toolbar:  Tell A Friend  |  Add to favorites  |  Feedback  |