DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 9.3 Caching Data

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 Web Forms page 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 code for the Web Forms page is shown in Example 9-3.

Example 9-3. File: ADOCookbookCS0903.aspx
<form id="ADOCookbookCS0903" method="post" runat="server">
    <asp:HyperLink id="HyperLink1"
        style="Z-INDEX: 101; LEFT: 16px; POSITION: absolute; TOP: 24px"
        runat="server" NavigateUrl="default.aspx">Main Menu
    </asp:HyperLink>
    <asp:DataGrid id="customersDataGrid"
        style="Z-INDEX: 102; LEFT: 16px; POSITION: absolute; TOP: 128px"
        runat="server" AllowPaging="True">
        <HeaderStyle Font-Bold="True"></HeaderStyle>
    </asp:DataGrid>
    <asp:Label id="cacheStatusLabel"
        style="Z-INDEX: 103; LEFT: 16px; POSITION: absolute; TOP: 96px"
        runat="server" ForeColor="Green"></asp:Label>
    <asp:Button id="clearCacheButton"
        style="Z-INDEX: 104; LEFT: 16px; POSITION: absolute; TOP: 56px"
        runat="server" Text="Clear Cache">
    </asp:Button>
</form>

The code-behind contains three event handlers and two methods:

Page.Load

Checks the cache for an object with the key CustomerDataSet. If an entry is not found, the DataSet is loaded by calling the LoadDataSet( ) method. If an entry is found, the cached object is retrieved and cast to a DataSet. In either case, the source of the data is displayed to the user. If the page is being loaded for the first time, the CurrentPageIndex of the data grid on the page is set to 0 (the first page) and the BindDataGrid( ) method is called to bind the default view of the Customers table to the data grid on the form.

LoadDataSet( )

This method loads a DataSet with the Customers table from the Northwind database. The DataSet is added to the cache with the key CustomerDataSet and an expiration time of 15 seconds into the future.

BindDataGrid( )

This method binds the default view of the Customers table in the DataSet to the DataGrid on the page. The key for the DataGrid is set to the CustomerID field.

DataGrid.PageIndexChange

Sets the current page index of the DataGrid to the new value of the page index. The BindDataGrid( ) method is called.

Clear Button.Click

Removes the DataSet containing the Customers data from the cache.

The C# code for the code-behind is shown in Example 9-4.

Example 9-4. File: ADOCookbookCS0903.aspx.cs
// Namespaces, variables, and constants
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;

//  . . . 

private void Page_Load(object sender, System.EventArgs e)
{
    // Load the data from database or cache and
    // display where the data came from.
    if(Cache["CustomersDataSet"] == null)
    {
        LoadDataSet( );
        cacheStatusLabel.Text = "DataSet retrieved from database.";
    }
    else
    {
        ds = (DataSet)Cache["CustomersDataSet"];
        cacheStatusLabel.Text = "DataSet retrieved from cache.";
    }

    if(!Page.IsPostBack)
    {
        // When page is first opened, position to first grid page.
        customersDataGrid.CurrentPageIndex = 0;
        BindDataGrid( );
    }
}

private void LoadDataSet( )
{
    // Create a DataAdapter.
    String sqlText = "SELECT * FROM Customers";
    SqlDataAdapter da =
        new SqlDataAdapter(sqlText,
        ConfigurationSettings.AppSettings["DataConnectString"]);
    ds = new DataSet( );
    // Fill the a customers table in the DataSet with all customers.
    da.Fill(ds, "Customers");

    // Save the DataSet to the cache expiring in 15 seconds.
    Cache.Insert("CustomersDataSet", ds, null,
        DateTime.Now.AddSeconds(15), System.TimeSpan.Zero);
}

private void BindDataGrid( )
{
    // Bind the default view of the customers table to the grid.
    customersDataGrid.DataSource = ds.Tables["Customers"].DefaultView;
    customersDataGrid.DataKeyField = "CustomerID";
    customersDataGrid.DataBind( );
}

private void customersDataGrid_PageIndexChanged(object source,
    System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
    // Change the current page of the grid and rebind.
    customersDataGrid.CurrentPageIndex = e.NewPageIndex;
    BindDataGrid( );
}

private void clearCacheButton_Click(object sender, System.EventArgs e)
{
    // Remove the cache when user presses "clear" button.
    Cache.Remove("CustomersDataSet");
    cacheStatusLabel.Text = "Cache cleared.";
}

Discussion

Data used by an application can be recreated in each roundtrip to the server or it can be cached and retrieved from the cache in subsequent page processing. Recreating data tends to improve its accuracy; however, this can require significant additional processing. Caching data, on the other hand, uses more system resources to store the data, which can become a problem if many users are caching data.

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

    [ Team LiB ] Previous Section Next Section