Accessing and Updating Data in ASP.NET: Declaratively Caching DataBy Scott Mitchell
The ASP.NET 2.0 data source controls provide a declarative means for accessing and working with data. Simply set a few properties of the data source control, bind it to a data Web control, and, voila, data is being retrieved and displayed without having written a single line of code!
In addition to working with data declaratively, the data source controls can also cache data declaratively. Caching is a common technique used in data-driven applications to boost performance, and works by storing database data in memory where it can be more efficiently accessed. ASP.NET provides the data cache, which is a programmatically-accessible cache that is commonly used to store database results. See Caching in ASP.NET for more details on using the data cache and other caching options in ASP.NET.
What's worth noting about the data source controls is that they offer declarative access to the data cache. By simply setting a few properties, the data source controls will happily store their retrieved data in the data cache. Then, the next time the data source is asked to retrieve data, they'll pull that data from the cache instead of returning to the database. In this article we'll explore how to setup a data source control so that it stores it caches its results. Read on to learn more!
A Quick Primer on Caching
Caching is a technique for improving performance by moving data from some expensive data store to one that is less so. By "expensive" I mean that there is a performance cost associated with working with the data and by "data store" I mean some location where data is stored: a database, a file, memory, and so forth. The canonical caching example is taking information from a database and storing it in an application's memory, since an application can read from its memory many orders of magnitude faster than it can read the same data from a remote database server.
Caching carries with it some limitations. Almost always, the more efficent data store has less storage space than the slower store. That is, chances are the database holds a lot more information than can fit in the application's memory. Therefore, not all data can be cached. Moreover, when adding data to the cache, other cached information might need to be evicted from the cache in order to make room.
Also, caching imposes a disconnect between data the application sees and the source data itself. If the source data is updated or deleted, the application working with a cached copy won't know that it's data has become stale until it returns to the original data store and determines that this, indeed, is the case. For this reason, data is typically only cached for a pre-determined duration, after which the data is automatically evicted. This places an upperbound on how long the cached data may be stale. (ASP.NET 2.0 offers SQL cache dependencies, which is a more proactive technique for determining if the cached data has become stale. This article does not explore SQL cache dependencies, but see the "Further Readings" section at the end for more information on this topic.)
The data cache is the cache store commonly used by ASP.NET applications. It is an in-memory cache that is accessible
Cache object. The data cache provides dictionary-like access to its contents. To add an item to the
cache, specify a key for that cache item, where the key is a string. Likewise, to retrieve an item from the cache, refer to it via its key. The following
code snippet shows reading and writing to the data cache:
Caching Data Retrieved from the Data Source Controls
The ObjectDataSource, SqlDataSource, AccessDataSource, and XmlDataSource controls all contain properties that instruct the data source control to cache its data in the data cache. This caching occurs automatically and requires no code from us, the page developer. The key properties are:
EnableCaching- a Boolean value that indicates whether or not caching should be applied. Defaults to False. You will need to set this to True to instruct the data source control to employ caching.
CacheDuration- an Integer value that indicates the duration the data should be cached (in seconds).
CacheExpirationPolicy- specifies the cache expiration behavior; can be set to Absolute or Sliding. Absolute means that the cached item will be evicted CacheDuration seconds from when the item is initially inserted into the cache. Sliding means that the item will be evicted CacheDuration seconds after the last time the data is accessed from the cache. The default is Absolute.
CacheKeyDependency- a String value that specifies an additional item in the cache that serves as a dependency. If this value is specified, then whenever the cache item CacheKeyDependency is modified, the data source will automatically evict its data from the cache as well.
SqlCacheDependencyproperty that should be used if you are using SQL cache dependencies. Also note that while the AccessDataSource has this property, attempting to use it in will result in a
NotSupportedExceptionexception to be thrown. Also note that the data source controls will only cache data if
EnableCachingis set to True and either a time-based expiry is specified via the
CacheDurationproperty or a SQL cache dependency is specified.
The following declarative syntax shows an AccessDataSource that is configured to support caching for an absolute duration of 30 seconds (also be sure to check out the more in-depth demos available for download at the end of this article):
When this AccessDataSource's
Select method was invoked by a data Web control (such as a GridView), the AccessDataSource
would first see if its data was in the data cache. If not, it would connect to the Microsoft Access database (
and issue the
SelectCommand query. It would then cache the results in the data cache and return them to the
requesting data Web control. Now, imagine that five seconds later another user visits the page. The data Web control will
again request the AccessDataSource for its data, but this time the data will be in the cache. Therefore, the AccessDataSource
will return its data to the data Web control without having to connect to the database. After 30 seconds, though, the
data will be evicted from the cache and the subsequent request will go back to the database.
A Detailed Look at How the Data Source Caches its Data
Selectmethod is invoked for a data source control that has been configured for caching, the data source control starts by checking to see if its data resides in the data cache. As mentioned earlier, the data cache's items are accessed by a string key. The key used by the data source control is a combination of its essential properties. For the SqlDataSource, this includes the value of the
SelectParametersproperties. This ensures that the cache is unique per the connection, per the
SELECTquery, and per the
SELECTquery's parameter names and values (if any).
If the item is found in the data cache, the data source control returns the cached data and does not raise its
Selecting event. As discussed in the Examining
the Data Source Control's Events article, the
Selecting event fires each time the data source control's
Select method is invoked and data is retrieved from the underlying store.
If the item is not found in the cache, then the data source control proceeds through its normal selecting workflow: the
Selecting event fires, the underlying data store is accessed and data retrieved, and the
event fires. Before the data is returned, however, the data source control first adds it to the data cache, using the same
key construction process discussed above.
The following sequence diagram depicts the caching workflow for the ObjectDataSource, although the workflow is identical for
the AccessDataSource, SqlDataSource, and XmlDataSource controls as well. Note how the
Selecting event does not
first if the item is served from the cache.
We can use the fact that the
Selecting event only fires when the data is retrieved from the underlying data
store to display information on a page of when the data was last cached. The examples available for download at the end of this
article use a Label Web control that's updated with the current date and time each time the
Selecting event fires,
thereby showing the most recent time the cache was updated. While an end user might not care or need to see this information,
it's helpful for page developers as it shows when cached data is being stored and what actions can cause the cached data to
be prematurely evicted.
Evicting Items from the Cache
One downside of caching is stale data. While a short time-based expiry can help limit the total duration of potentially stale data, there are other actions that can be taken to forcibly evict an item from the data cache. The data source controls will automatically remove their data from the cache if the data source control's
Deletemethods are invoked. We've yet to explore these data modification methods available in the data source controls, but we most certainly will in a future installment. In short, these methods modify the underlying data store, as their names imply, and can be configured declaratively. When any of these methods are executed, the data source control is modifying the underlying data store, so it makes sense for the data source control to evict the cached data since it now knows that that data is stale. You can see this behavior in the examples available for download at the end of this article.
You can also programmatically remove the data source control's cached data by using the
Simply set the
CacheKeyDependency property to the key value of some data in the cache. Then, to remove the
data source control's cached data, simply update the cache item
Start by setting the data source control's
CacheKeyDependency property to the name of the cache item key you
want to serve as a dependency. You can choose any old name for this property:
Next, it's imperative that this item exists in the cache, otherwise the data cached by the data source control will be immediately
evicted from the data cache each time its added. In the
Page_Load event handler, test to see if the
item exists in the cache and, if not, add it:
Here I assign
DateTime.Now to the cache item, but you can use any value.
DateTime.Now is a good
choice, though, because it indicates the last time the cache item was last updated.
To programmatically evict the data source's cached data, simply update the value of the
cache item, such as to the current date and time (
Cache(ProductsDataSource.CacheKeyDependency) = DateTime.Now). In the download at the end of this article there's an example that includes
a Button Web control that, when clicked, evicts the data from the cache by updating
to the current date and time. That's all there is to it!
The data source controls make accessing and working with data as easy as setting a few properties. Oftentimes, no code is required. As we saw in this article, this declarative model is also extended to caching. A data source control's data can be cached in the data cache using a time-based expiry simply by setting the
EnableCachingproperty to True and the
CacheDurationproperty to the duration the data should be cached (in seconds). The SqlDataSource and ObjectDataSource controls can also use SQL cache dependencies, although this topic will have to wait for a future article.