Problem
Given a Web Forms application that is performing poorly because it is repeatedly reading data that doesn't change very often, you need to cache the data to eliminate unnecessary queries and improve the performance.
Solution
Use the ASP.NET Cache class.
The solution has a Web Form that defines the data grid used to display the contents of a
DataSet, a button to clear the cache, and a label that displays whether the data was retrieved from the cache or from the database. The C# code for the Web Forms page
Default.aspx in the project
CachingData.
Default.aspx for CachingData solution
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CachingData.Default" %> <!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>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<br />
<asp:Button ID="clearCacheButton" runat="server" Text="Clear Cache" OnClick="clearCacheButton_Click" /> <br />
<asp:Label ID="cacheStatusLabel" runat="server" ForeColor="Green" /> <br />
<asp:GridView ID="departmentGridView" runat="server" AllowPaging="True" OnPageIndexChanging="departmentGridView_PageIndexChanging">
<HeaderStyle Font-Bold="True"></HeaderStyle>
</asp:GridView>
</form>
</body>
</html>
The code-behind for the page checks the
Cache for a
DepartmentDataSet object. If there is no entry, a
DataSet instance
ds is loaded with the
Person.Department table in
AdventureWorks and inserted to the cache with an expiration time of 15 seconds. In either case, the source of the department data—cache or database—is displayed on the web page. If the
DepartmentDataSet object exists in the
Cache, it is cast to a
DataSet and loaded into the
DataSet instance named
ds . The
DataSet is bound to a
DataGridView. In addition to a 15-second expiration, the
clearCacheButton manually removes the
DepartmentDataSet object from the
Cache when it is clicked.
The C# code for the code-behind Default.aspx.cs in CachingData.
Default.aspx.cs for CachingData solution
using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.UI.WebControls;
namespace CachingData
{
public partial class _Default : System.Web.UI.Page
{
private DataSet ds;
protected void Page_Load(object sender, EventArgs e)
{
// Load the data from database or cache and // display where the data came from. if (Cache["DepartmentDataSet"] == null) {
LoadDataSet();
cacheStatusLabel.Text = "DataSet retrieved from database.";
}
else {
ds = (DataSet)Cache["DepartmentDataSet"];
cacheStatusLabel.Text = "DataSet retrieved from cache.";
}
if (!Page.IsPostBack)
{
// When page is first opened, position to first grid page.
departmentGridView.PageIndex = 0;
BindDataGrid();
}
}
private void LoadDataSet()
{
string sqlConnectString = "Data Source=(local);" + "Integrated security=SSPI;Initial Catalog=AdventureWorks;";
string sqlText = "SELECT * FROM HumanResources.Department";
SqlDataAdapter da = new SqlDataAdapter(sqlText, sqlConnectString);
ds = new DataSet();
// Fill the Department table in the DataSet with all Department.
da.Fill(ds, "Department");
// Save the DataSet to the cache expiring in 15 seconds.
Cache.Insert("DepartmentDataSet", ds, null, DateTime.Now.AddSeconds(15), System.TimeSpan.Zero);
}
private void BindDataGrid()
{
// Bind the default view of the Department table to the grid.
departmentGridView.DataSource = ds.Tables["Department"].DefaultView; departmentGridView.DataKeyNames = new string[] {"DepartmentID"};
departmentGridView.DataBind();
}
protected void departmentGridView_PageIndexChanging( object sender, GridViewPageEventArgs e)
{
// change the current page of the grid and rebind
departmentGridView.PageIndex = e.NewPageIndex; BindDataGrid();
}
protected void clearCacheButton_Click(object sender, EventArgs e)
{
// Remove the cache when user presses "clear" button.
Cache.Remove("DepartmentDataSet");
cacheStatusLabel.Text = "Cache cleared.";
}
}
Output for CachingData solution
Disscussion
Data used
by an application can be re-created in each roundtrip to the server or it can be cached and retrieved from the cache in subsequent page processing. Re-creating data tends to improve its accuracy; however, this can require significant additional processing.
Caching data, on the other hand, uses more system resources, which can become a problem.
Data can be cached on the client—in the page using the view state—or on the server in a session state or application state variable or using a cache.
Client-side caching uses no server resources for the cache, but requires network bandwidth to transmit the cached information back and forth with each roundtrip to the server.
Server-side caching uses server-side resources but little bandwidth for caching. In either case, the amount of data cached should be minimized to optimize application performance and scalability.
ASP.NET implements a
System.Web.Caching.Cache class to store objects that require a lot of server resources to create so that they do not have to be re-created each time they are needed. Instances of the
Cache class are created for each application domain and remain active as long as the application domain remains active. When an application is restarted, its instance of the
Cache class is re-created. You can programmatically access information about an instance of the
Cache class through the
Cache property of either the
HttpContext object or the
Page object.
Data is placed in a
Cache object using key-and-value pairs. The
Add() method is used to create an entry for a new key value that will fail if the key already exists, while the
Insert() method will create either a new entry or overwrite an existing entry. The
Remove() method is used to remove a key-and-value pair from the
Cache object.
The
Cache class allows an
expiration policy to be established for items in the cache. Items can be set to expire at a specific time, called
absolute expiration, or after not being accessed for a specific period of time, called
sliding expiration. Items that have expired return a
null value. Generally, the expiration policy is set so that data is cached only as long as it remains current.
Caching data can improve performance by reducing the number of trips between the server and the data source. Drawbacks of
caching include server memory that is consumed by the cache and the data in the cache being out of sync with the data source.