Caching in ASP.NET

Caching is a technique that is used to store a replica of the data in memory. Caching is used to increase the performance of the web application. The copy of data exists in temporary storage, it means that when the data is no longer used then it expires automatically.

Accessing data from database table is time consuming task. If you want to do database programming then first open a database connection and perform the database operation (select, update, delete, insert), close the connection.  These database operations are very slow.

Caching enables you to cache your database records in memory.

The ASP.NET Framework supports the following types of caching:

  • Page Output Caching
  • Partial Page Caching
  • DataSource Caching
  • Data Caching

Page Output Caching

Page Output Caching caches an entire page. It enables you to cache the entire contents of a page in memory. If caching is used in the page and any user requests the same page, the page is retrieved from the cache. It will reduce the load of server and increases performance.

<%@ OutputCache %> directive is used to enable Page Output Caching in a page.

For example, the given below code will caches page contents for 15 seconds.

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ OutputCache Duration="15" VaryByParam="none" %>


Default.aspx.cs

protected void Button1_Click(object sender, EventArgs e)
{
     Label1.Text = DateTime.Now.ToString();
}


If you refresh the page several times within 15 seconds, then time will not be updated. The Duration attribute defines the number of seconds a page is stored in the cache.
If you have used caching technique, and user requests the same page, then the page is not recreated but rendered the cached page from cache.
It is not necessary that a page will be cached for the specified amount of time. When memory resources become low, then cached items are automatically deleted.

By default, when you use Caching the page is cached on the following location.

  • Browser
  • Proxy servers
  • Web server
OutputCache directive supports the following important attributes.

  • VaryByParam
  • VaryByHeader
  • VaryByCustom
  • VaryByControl
  • Location
  • Duration

VaryByParam attribute

VaryByParam attribute in OutputCache directive is used to cache the different version of the requested page when a different parameter is passed to the page. The VaryByParam is a compulsory parameter of the OutputCache directive.

Suppose that you are working with separate Master detail page. You passed the parameter from master page to detail page using QueryString object. If you have applied page output caching and VaryByParam parameter value is "None" on the details page, then everyone will see the same page.
You can remove this problem by using VaryByParam parameter.

<%@ OutputCache Duration="15" VaryByParam="id" %>

The VaryByParam attribute will create a new instance of a page, according to value passed VaryByParam attribute.

VaryByParam attribute supports two values as:

none: If you apply none to the VaryByParam attribute then only one version of the page is cached.

*: Whenever you change the value of parameter which is passed to the page, new version of page will be cached.

Example

EmpMaster.aspx.cs
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web.UI.WebControls;
using System.Web.UI;
public partial class EmpMaster: System.Web.UI.Page
{
    SqlConnection conn;
    SqlDataAdapter adapter;
    DataSet ds;
    SqlCommand cmd;
    string cs = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            PopulateGrid();
        }
    }
    protected void PopulateGrid()
    {
        try
        {
            conn = new SqlConnection(cs);
            adapter = new SqlDataAdapter("select * from tblEmps", conn);
            ds = new DataSet();
            adapter.Fill(ds);
            GridView1.DataSource = ds;
            GridView1.DataBind();
        }
        catch (Exception ex)
        {
            Label1.Text = "ERROR :: " + ex.Message;
        }
    }    
}


In the above example a GridView control is used. We have used HyperLinkField to bind the employee name from database table.

<Columns>
      <asp:HyperLinkField DataTextField="Name" HeaderText="Employee Name"
      NavigateUrl="∼/EmpDetail.aspx" DataNavigateUrlFields="EmpID"
      DataNavigateUrlFormatString="EmpDetail.aspx?id={0}" />
</Columns>


When user clicks on name of any employee, the ID of that employee will pass to the page EmpDetail.aspx through the QueryString. Because we pass the ID in VaryByParam attribute also, so every time we will get new instance of Employee Detail page. The Employee Detail page contains a DetailsView control to display detailed information of the employee, which is selected from the employee master page.

EmpDetail.aspx.cs

using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web.UI.WebControls;
using System.Web.UI;

public partial class EmpDetail : System.Web.UI.Page
{
    SqlConnection conn;
    SqlDataAdapter adapter;
    DataSet ds;
    SqlCommand cmd;
    string cs = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            PopulateDetailView();
        }  
    }
    protected void PopulateDetailView()
    {
        try
        {
            int id=Convert.ToInt32( Request.QueryString["id"]);
            conn = new SqlConnection(cs);
            adapter = new SqlDataAdapter("select * from tblEmps where empid="+id, conn);
            ds = new DataSet();
            adapter.Fill(ds);
            DetailsView1.DataSource = ds;
            DetailsView1.DataBind();
        }
        catch (Exception ex)
        {
            Label1.Text = "ERROR :: " + ex.Message;
        }
    }
}


Output:            

page output caching

Partial Page Caching

Page output caching caches the whole output of a page. Generally a web page contains static and dynamic contents. For example the data coming from database is not as frequently change as the advertisements changes. Therefore you would not wish to cache whole page because advertisements changes frequently.

Partial page caching enables you to cache portion of a page. It is also called as control caching or fragment caching.

Normally partial caching is performed using the "User Control". You can do caching with the help of user control as same as page output caching but you have to do caching in user control.

First add a user control in your web project and write code as given below. In this application the user control name is TimeUserControl

TimeUserControl.ascx

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


TimeUserControl.ascx.cs

using System;
public partial class TimeUserControl : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Label1.Text = "User Control Time </br> (Cached Time) =: " + DateTime.Now.ToString("hh:mm:ss");
    }
}


Use this user control on web page and do the following coding.

protected void Page_Load(object sender, EventArgs e)
{
     Label1.Text = "Normal Time =: " + DateTime.Now.ToString("hh:mm:ss");
}


The content of user control will be cached 30 seconds. If you refresh the page within 30 seconds, the user control time will not be change but the time that is available in web page is going to change every time when you postback the page or refresh.

partial page caching

Using Data Caching

The most important object in caching mechanism is cache object. The Cache object is the fundamental object for all caching in the ASP.NET Framework.

The cache object can be accessed in every page of your application. It works same as Session object. Storing and retrieving the object in cache is very easy.

Cache["Key"]="Item";

Normally you store database object in Cache, so it will reduce the database calling again and again.

Some of the important methods of Cache object are as follows:

  • Add: It adds a new item to the cache.
  • Get: It returns a particular item from the cache.
  • Insert: It is used to insert a new item into the cache. This method replaces the already exists item.
  • Remove: This method is used to remove an item from the cache.
Cache is a powerful object, you can add into it DataSet, DataTable, ArrayList etc.

Now let’s take an example and create a web application in which we will take two web pages. In first page, we will add the dataset object into the cache and then access this cached data from second page.

FirstPage.aspx.cs

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
public partial class FirstPage : System.Web.UI.Page
{
    SqlConnection conn;
    SqlDataAdapter adapter;
    DataSet ds;
    
    string cs = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
    protected void Page_Load(object sender, EventArgs e)
    {
        ds=new DataSet();
        conn = new SqlConnection(cs);
        adapter = new SqlDataAdapter("select * from tblEmps", conn);      
        adapter.Fill(ds);
        Cache["Data"] = ds;       
    }
    
    protected void Button1_Click(object sender, EventArgs e)
    {
        Response.Redirect("SecondPage.aspx");
    }
}


Now you can use Cache["Data"] object in any web page of your application. Cache returns the Object type, therefore you must typecast to underlying data type.

SecondPage.aspx.cs

using System;
using System.Data;
public partial class SecondPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        DataSet ds=(DataSet)Cache["Data"];
        GridView1.DataSource = ds;
        GridView1.DataBind();
    }
}


Adding Items to the Cache

Insert() method is used to add items to the cache. Insert() method have several overloaded method. Insert method can accept following parameters in different version of overloaded method.

  • Key: It specifies the name of the new item.
  • Value: It specifies the value of the new item.
  • Dependencies: It supports the file, key, or SQL dependency. You can apply any of dependencies at a time.
  • absoluteExpiration: DataTime object is used to specify the time duration. It is used to specify an absolute expiration time for the cached data. After that data is removed automatically from the cache.
  • slidingExpiration: DataSpan object is used to specify the time duration. It is used to specify a sliding expiration duration for the cached data.
  • Priority: It is used to set the priority of the cached item. You can use any of the following value  AboveNormal, BelowNormal, Default, High, Low, Normal, and NotRemovable.

Adding Items with an Expiration Policy

You can add different data object in cache object. When the memory is going to full, the server will automatically remove the item from cache. You can also specify an expiration time when the item will remove from the cache.

We can add the object into the cache by using insert() method. The cache.insert() method has 4 overloaded methods.

There are two different ways to expire the cache on the basis of time.

1. Absolute Expiration
2. Sliding Expiration

Absolute Expiration: This policy is useful when you know that your data does not change frequently. As its name suggests, the data from the cache will be removed after specified time, irrespective of whether cached data is accessed from cache or not. In absolute expiration DataTime object is used to specify the time duration.

Example

string strData = "The string data to be cached";        
Cache.Insert("AbsoluteCacheKey", strData, null,
DateTime.Now.AddMinutes(1), System.Web.Caching.Cache.NoSlidingExpiration);


Sliding Expiration: It defines that how long the data should remain available in the cache after the data was last accessed. It keeps the most frequently accessed items in memory. In sliding expiration TimeSpan object is used to specify the time duration.

Example

Cache.Insert("SlidingExpiration", strData, null,
System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1));


In the above examples, we have used string data type for caching, but you can use DataSet, DataTable, ArrayList or other type of data.
We cannot use absolute expiration and sliding expiration policies simultaneously. If you try to do it, it will give you runtime error.

Cache dependency on files

Suppose that we have data in a file and this data is cached for some specified time duration. If you want that whenever the file data is modified, the cached data is automatically removed from the cache. For this to happen we need to provide a dependency on the file.
First we will add a XML file in our project and write data as given below.

<?xml version="1.0" encoding="utf-8" ?>
<EmployeeInfo>
     <Employee>
          <EmpID>1</EmpID>
          <Name>Raj</Name>
          <Address>Pune</Address>
     </Employee>
     <Employee>
          <EmpID>2</EmpID>
          <Name>Shiva</Name>
          <Address>USA</Address>
     </Employee>
     <Employee>
          <EmpID>3</EmpID>
          <Name>Digvijay</Name>
          <Address>NewYork</Address>
     </Employee>
</EmployeeInfo>


Now take a GridView, a button, and a label on the web page and write code for access the EmployeeInfo.xml file.

using System;
using System.Data;
using System.Web.Caching;
public partial class DepandencyDemo : System.Web.UI.Page
{    
    protected void Page_Load(object sender, EventArgs e)
    {         
    }    
    protected void btnGetEmp_Click(object sender, EventArgs e)
    {
        if (Cache["EmpData"] != null)
        {
            DataSet ds = (DataSet)Cache["EmpData"];
            GridView1.DataSource = ds;
            GridView1.DataBind();
            Label1.Text = ds.Tables[0].Rows.Count.ToString()+"  records are retrieved from cache";
        }
        else
        {
            DataSet ds = new DataSet();
            ds.ReadXml(MapPath("∼/EmployeeInfo.xml"));
            Cache.Insert("EmpData", ds, new CacheDependency(MapPath("∼/EmployeeInfo.xml")), DateTime.Now.AddMinutes(1) Cache.NoSlidingExpiration);
            GridView1.DataSource = ds;
            GridView1.DataBind();
            Label1.Text = ds.Tables[0].Rows.Count.ToString() + "  records are retrieved from EmployeeInfo.xml file";
        }
    }
}


When you click on get employee button, the GridView control access the data from xml file and data will be cached for 60 seconds. This data is cached for 60 seconds in cache. If we change the xml file data within 60 seconds, the cached data will automatically remove and updated data will be cached.

If we write "null" in place of new CacheDependency(MapPath("∼/EmployeeInfo.xml")), then dependency will not apply.

cache dependency on files