Displaying Cached XML Data in a DataGrid, and Intelligently Refreshing the DataBy Scott Mitchell
One of the coolest and most powerful aspects of the .NET Framework is the built-in caching APIs. These caching APIs make caching through ASP.NET Web pages painfully simple. When discussing caching with regards to an ASP.NET Web page there are two classes of caching: output caching and data caching.
Output caching is the caching of the HTML output of an ASP.NET Web page. This cached HTML is stored on disk and is cached for a specific period of time (say 30 seconds). With data caching, programming objects (such as integers, DataSets, ArrayLists, etc.) are stored in an in-memory cache. Items stored in the data cache can have their expiration specified by a sliding time scale, an absolute time scale, or via a cache dependency. A cache dependency can be a file or a directory in the file system, or a key in the cache. When the dependency changes - the file is modified, the directory is altered, or the cache item is altered or evicted - the item with the cache dependency is evicted from the cache.
In this article we will first look at caching a DataSet in the data cache, and binding this cached DataSet to a DataGrid. Specifically, this cached DataSet will contain the data from an XML file residing on the Web server's file system. A cache dependency will then be used so that the cached DataSet is evicted from the data cache when the XML file's contents are altered. In essence we will be examining how to create a DataGrid that displays cached data, but whose data is never stale! (That is, whenever the data changes, the cached version of the data is updated as well.)
Displaying XML Data in a DataGrid
In a previous 4Guys article, XML, the DataSet, and a DataGrid, I looked at how to display XML data in a DataGrid. The first step in accomplishing this is reading the XML data into a DataSet. Once we have the data in a DataSet, we can simply bind the DataSet to the DataGrid's
DataSourceand then call the DataGrid's
|For More Information on the DataGrid...|
|If you're not familiar with the DataGrid Web control I would encourage you to first read an earlier article of mine: An Extensive Examination of the DataGrid Web Control. It is a multi-part series that covers the ins and outs of the DataGrid Web control.|
Reading XML data into a DataSet is incredibly simple thanks to the DataSet's
This method takes in a string parameter as the filename to the XML file.
In the above example, the
Server.MapPath() method is used to obtain the full physical path
books.xml file. (For more information on
Server.MapPath() be sure to
Once we have a DataSet populated with the results of an XML file, we can display the DataSet in a DataGrid Web control using the following two lines of code:
The following code snippet shows the complete code for an ASP.NET Web page that displays the contents
of the file
Caching the DataSet
Now that we have seen how to populate a DataSet with the contents of an XML file, let's turn our attention to caching this DataSet in the data cache. This article does not intend to be a thorough examination of the data cache, as there are already a number of articles already on this topic. If you are interested in learning more about caching options available with ASP.NET, I'd highly recommend Scott McFarland's Caching with ASP.NET article.
To bind the DataGrid to a cached DataSet, we first must check that the DataSet is in the cache. After
all, it may have never been added, or it may have been evicted from the cache for one of any number of
reasons. To determine if an item is in the cache, we can simply check to see if the item is
(In C# you'd check to see if the cache item equaled
null.) The following code checks to
see if the cache item
authorsDS is in the cache or not.
In the case that there is no
authorsDS item in the cache, we want to add it. This can be
accomplished using the
Cache.Insert() method. Before adding the DataSet to the cache, though,
we must populate it from the XML file, as we saw earlier. This code, then, looks like:
When the end of this conditional statement is reached, we know for certain that there exists a cache item
authorsDS (that should have a cached DataSet populated from the
file). If, when the page is visited, the cache item does not exist, it is created and added to the cache.
If, on the other hand, when the page is visited the cache item does exist, then we don't need to populate
the DataSet with the XML file contents, since the contents are already populated in a cached DataSet.
All that's left to do here is bind the cached DataSet to a DataGrid, which is accomplished using the following complete code example:
Notice that a Label Web control was added (
lblMessage) that is used to display a helpful
debugging message when the DataSet was not found in the cache. If you try this example on your own
computer, you'll find that the first time you visit the page it indicates that the DataSet was populated
from the XML file; however, if you reload the page, this message does not appear, since the DataSet
is cached, and the DataGrid is using the cached version.
Caching the Data in a More Intelligent Manner
One downside, though, is that when using cached data, the data may become stale. For example, if you visit the page with the cached DataSet once, to load the DataSet into the cache, and then the contents of the XML file are changed, the cached DataSet page will continue to show the cached data. That is, your users will see the data prior to the change in the XML file.
Ideally we'd like to be able to have the cached data reside in the cache so long as the underlying XML data doesn't change. To put it another way, as soon as the XML file's contents change, we want the cached DataSet to be evicted from the cache. We can accomplish this goal using cache dependencies.
As mentioned in the Introduction, cache dependencies can be a file (or files) or a directory in the
file system, or a key in the cache. When the dependency changes - the file is modified, the
directory is altered, or the cache item is altered or evicted - the item with the cache dependency is
evicted from the cache. This sounds exactly like what we need! Essentially, the
file will become the cache dependency for the cached DataSet. This will cause the cached DataSet to be
evicted from the cache whenever the
books.xml file is altered.
To add an item to the cache with a cache dependency, we simply need to use an alternate version of the
Cache.Insert() method. Specifically, we need to pass in a
object instance as the third parameter to
Cache.Insert(). This requires just a small edit to
our earlier code sample, which now gives us:
And that's all there is to it! Now, when you try the above code on your computer you'll find that
when you first visit the page the message "DataSet populated from XML file..." appears, but on subsequent
visits, the message is no longer there. The cool part - if you edit the
books.xml file (say
add a new
book element), and then revisit the page, you'll note that the DataGrid is displaying
the new book and that the "DataSet populated from XML file..." message has appeared again. This is because
the cached DataSet is evicted from the cache whenever edits occur to the underlying XML file.
|For More Information...|
|For more information on caching and using cache dependencies, be sure to check out Dino Esposito's article Using Session and Application Objects in ASP.NET. For a tutorial showing how to use on-demand cache eviction for data in a SQL Server database (as opposed to in an XML file) see Donny Mack's Invalidating an ASP.NET Web Application Cache Item from SQL Server.|
In this article we saw how to accomplish a number of things, which include: populating a DataSet with data from an XML file; caching a DataSet in the data cache; and using cache dependencies to provide on-demand cache eviction when the underlying XML data is altered. This approach has the performance benefits inherent with caching, and removes one of the primary disadvantages of caching: stale data.