Recipe 13.6 Caching Application Data

     

13.6.1 Problem

Your application draws on data that is expensive to create from a performance perspective, so you want to store it in memory, where it can be accessed by users throughout the lifetime of the application. The problem is that the data changes occasionally and you need to refresh the data when it changes.

13.6.2 Solution

Place the data in the Cache object with a dependency set to the source of the data so the data will be reloaded when it changes. Example 13-3 and Example 13-4 show the code we've written to demonstrate this solution. In this case, these are VB and C# code-behind files for Global.asax that place some sample XML book data in the Cache object. In our example, the book data is automatically removed from the cache anytime the XML file is changed.

13.6.3 Discussion

The Cache object in ASP.NET provides the ability to store application data in a manner similar to the storing of data in the Application object. The Cache object, unlike the Application object, lets you specify that the cached data is to be replaced at a specified time or whenever there is a change to the original source of the data.

In Example 13-3 and Example 13-4, two methods have been added to global.asax.vb (or global.asax.cs for C#). The first method ( getBookData ) provides access to the data stored in the Cache object with the appropriate checking (to ensure the data is still valid) and reloading as required. The getBookData method performs the following operations:

  1. Gets a reference to the book data in the Cache object

  2. Checks the reference to ensure the data is still valid and reloads the data using the loadBookDataInCache method if it is not

  3. Returns a reference to the book data

The second method ( loadBookDataInCache ) provides the ability to initially load the book data into the Cache . It performs the following operations:

  1. Reads the book data from the XML file into a DataSet

  2. Stores the DataTable in the DataSet in the Cache object

  3. Returns a reference to the book data

When the DataTable in the DataSet is stored in the Cache object, three parameters are passed to the Insert method of the Cache object. The first parameter is the "key" value used to access the data in the cache. A constant is used here since the key value is needed in several places in the code. The second parameter is the DataTable containing the book data. The third parameter is the dependency on the XML file that was the original source of the data. By adding this dependency, the data is automatically removed from the cache anytime the XML file is changed.

A DataTable is being stored in the Cache object instead of a DataSet because it uses less system resources and the extra functionality of a DataSet is not needed.


 
figs/vbicon.gif
 context.Cache.Insert(CAC_BOOK_DATA, _ ds.Tables(BOOK_TABLE), _ New CacheDependency(xmlFilename)) 
figs/csharpicon.gif
 context.Cache.Insert(CAC_BOOK_DATA, ds.Tables[BOOK_TABLE], new CacheDependency(xmlFilename)); 

The getBookData method is added to global.asax.vb (or global.asax.cs for C#) to provide access to the data stored in the Cache object with the appropriate checking to ensure the data is still valid and reloading it as required.

The first step to retrieving the cached data is to get a reference to the book data in the Cache object:

 
figs/vbicon.gif
 bookData = CType(context.Cache.Item(CAC_BOOK_DATA), _ DataTable) 
figs/csharpicon.gif
 bookData = (DataTable)(context.Cache[CAC_BOOK_DATA]); 

Next , the reference must be checked to ensure the data is still valid and, if it is not, the data must be reloaded using the loadBookDataInCache method:

 
figs/vbicon.gif
 If (IsNothing(bookdata)) Then 'data is not in the cache so load it bookData = loadBookDataInCache(context) End If 
figs/csharpicon.gif
 if (bookData == null) { // data is not in the cache so load it bookData = loadBookDataInCache(context); } 

Finally, the book data is returned to the caller.

Avoiding Race Conditions

The code shown in our example is designed to avoid a race condition that can result in a very difficult-to-find error. The race condition is best described by example. Assume the following code was used (VB code shown):

 1 If (IsNothing(context.Cache.Item(CAC_BOOK_DATA)) then 2 loadBookDataInCache(context) 3 End If 4 bookData = Ctype(context.Cache.Item(CAC_BOOK_DATA), _ DataTable) 

The code shown on line 1 checks to see if the book data exists in the cache, but it does not retrieve the data. If the data was valid, the next line of code that would execute would be line 4. If the dependency caused the data to be removed from the cache between the execution of lines 1 and 4, a null reference exception would be thrown at line 4. because the data is no longer in the cache.

This example precludes the problem by retrieving the data as the first step then checks to see if the data is valid. Because you already have a copy of the data, you do not care if the data is removed from the cache. Likewise, the loadBookDataInCache method returns the data to avoid the same race condition problem.


The caching object provides many additional features not described in our example, including the ability to replace the data based on a specified time and the ability to have one object in the cache be dependent on another object in the cache. For more information on these topics, refer to the MSDN documentation on the Cache and CacheDependency objects.

One dependency that is not provided is the ability to replace the data when data in a database changes. A workaround is to write the data to an XML document when the application starts, and then use the approach shown in this example. When an operation changes the data in the database, the XML document can be regenerated, which will cause the data to be removed from the cache and then reloaded when it is needed the next time.

13.6.4 See Also

MSDN documentation on the Cache and CacheDependency objects

Example 13-3. Using application data in cache (.vb)
 Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: Global.asax.vb ' ' Description: This module provides the code behind for the ' Global.asax page ' '***************************************************************************** Imports Microsoft.VisualBasic Imports System Imports System.Configuration Imports System.Data Imports System.Data.OleDb Imports System.Diagnostics Imports System.Web Imports System.Web.Caching Namespace ASPNetCookbook.VBExamples Public Class Global Inherits System.Web.HttpApplication 'the following constant used to define the name of the variable used to 'store the book data in the cache object Private Const CAC_BOOK_DATA As String = "BookData" '************************************************************************* ' ' ROUTINE: loadBookDataInCache ' ' DESCRIPTION: This routine reads the book data from an XML file and ' places it in the cache object. '-------------------------------------------------------------------------  Private Shared Function loadBookDataInCache(ByVal context As HttpContext) _   As DataTable   Const BOOK_TABLE As String = "Book"   Dim xmlFilename As String   Dim ds As DataSet   'read book data from XML file   xmlFilename = context.Server.MapPath("xml") & "\books.xml"   ds = New DataSet   ds.ReadXml(xmlFilename)   'store datatable with book data in cache scope with a   'dependency to the original XML file   context.Cache.Insert(CAC_BOOK_DATA, _   ds.Tables(BOOK_TABLE), _   New CacheDependency(xmlFilename))   'return the data added to the cache   Return (ds.Tables(BOOK_TABLE))   End Function 'loadBookDataInCache  '************************************************************************* ' ' ROUTINE: loadBookDataInCache ' ' DESCRIPTION: This routine gets the book data from cache and reloads ' the cache if required. '-------------------------------------------------------------------------  Public Shared Function getBookData(ByVal context As HttpContext) _   As DataTable   Dim bookData As DataTable   'get the book data from the cache   bookData = CType(context.Cache.Item(CAC_BOOK_DATA), _   DataTable)   'make sure the data is valid   If (IsNothing(bookData)) Then   'data is not in the cache so load it   bookData = loadBookDataInCache(context)   End If   Return (bookData)   End Function 'getBookData  End Class 'Global End Namespace 

Example 13-4. Using application data in cache (.cs)
 //---------------------------------------------------------------------------- // // Module Name: Global.asax.cs // // Description: This module provides the code behind for the // Global.asax page // //**************************************************************************** using System; using System.Configuration; using System.Data; using System.Data.OleDb; using System.Diagnostics; using System.Web; using System.Web.Caching; namespace ASPNetCookbook.CSExamples { public class Global : System.Web.HttpApplication { // the following constant used to define the name of the variable used to // store the book data in the cache object private const String CAC_BOOK_DATA = "BookData"; //************************************************************************ // // ROUTINE: loadBookDataInCache // // DESCRIPTION: This routine reads the book data from an XML file and // places it in the cache object. //------------------------------------------------------------------------  private static DataTable loadBookDataInCache(HttpContext context)   {   const String BOOK_TABLE = "Book";   String xmlFilename = null;   DataSet ds = null;   // read book data from XML file   xmlFilename = context.Server.MapPath("xml") + "\\books.xml";   ds = new DataSet( );   ds.ReadXml(xmlFilename);   // store datatable with book data in cache scope with a   // dependency to the original XML file   context.Cache.Insert(CAC_BOOK_DATA,   ds.Tables[BOOK_TABLE],   new CacheDependency(xmlFilename));   // return the data added to the cache   return (ds.Tables[BOOK_TABLE]);   } // loadBookDataInCache  //************************************************************************ // // ROUTINE: getBookData // // DESCRIPTION: This routine gets the book data from cache and reloads // the cache if required. //------------------------------------------------------------------------  public static DataTable getBookData(HttpContext context)   {   DataTable bookData = null;   // get the book data from the cache   bookData = (DataTable)(context.Cache[CAC_BOOK_DATA]);   // make sure the data is valid   if (bookData == null)   {   // data is not in the cache so load it   bookData = loadBookDataInCache(context);   }   return (bookData);   } // getBookData  } // Global } 



ASP. NET Cookbook
ASP.Net 2.0 Cookbook (Cookbooks (OReilly))
ISBN: 0596100647
EAN: 2147483647
Year: 2006
Pages: 179

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net