ASP.NET 2.0 Unleashed

Behind the scenes, all the various caching mechanisms included in the ASP.NET Framework use the Cache object. In other words, the Cache object is the fundamental mechanism for all caching in the ASP.NET Framework.

One instance of the Cache object is created for each ASP.NET application. Any items you add to the cache can be accessed by any other page, control, or component contained in the same application (virtual directory).

In this section, you learn how to use the properties and methods of the Cache object. You learn how to add items to the cache, set cache expiration policies, and create cache item dependencies.

Using the Cache Application Programming Interface

The Cache object exposes the main application programming interface for caching. This object supports the following properties:

  • Count Represents the number of items in the cache.

  • EffectivePrivateBytesLimit Represents the size of the cache in kilobytes.

The Cache object also supports the following methods:

  • Add Enables you to add a new item to the cache. If the item already exists, this method fails.

  • Get Enables you to return a particular item from the cache.

  • GetEnumerator Enables you to iterate through all the items in the cache.

  • Insert Enables you to insert a new item into the cache. If the item already exists, this method replaces it.

  • Remove Enables you to remove an item from the cache.

For example, the page in Listing 23.35 displays all the items currently contained in the cache (see Figure 23.13).

Figure 23.13. Displaying the cache's contents.

Listing 23.35. EnumerateCache.aspx

<%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> Public Class CacheItem Private _key As String Private _value As Object Public ReadOnly Property Key() As String Get Return _key End Get End Property Public ReadOnly Property Value() As String Get Return _value.ToString() End Get End Property Public Sub New(ByVal key As String, ByVal value As Object) _key = key _value = value End Sub End Class Private Sub Page_Load() Dim items As New ArrayList() For Each item As DictionaryEntry In Cache items.Add(New CacheItem(item.Key.ToString(), item.Value)) Next grdCache.DataSource = items grdCache.DataBind() End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <style type="text/css"> .grid td, .grid th { padding:5px; } </style> <title>Enumerate Cache</title> </head> <body> <form runat="server"> <div> <asp:GridView Css Runat="server" /> </div> </form> </body> </html>

The page in Listing 23.35 displays only items that have been added to the cache by the methods of the Cache object. For example, it does not display a list of pages that have been output cached. Output cached pages are stored in the internal cache (the secret cache maintained by the ASP.NET framework).

Adding Items to the Cache

You can add items to the cache by using the Insert() method. There are several overloaded versions of the Insert() method. The maximally overloaded version of the Insert() method accepts the following parameters:

  • key Enables you to specify the name of the new item.

  • value Enables you to specify the value of the new item.

  • dependencies Enables you to specify one or more cache dependencies, such as a file, key, or SQL dependency.

  • absoluteExpiration Enables you to specify an absolute expiration time for the cached item. If you don't need to specify a value for this property, use the static field Cache.NoAbsoluteExpiration.

  • slidingExpiration Enables you to specify a sliding expiration interval for the cached item. If you don't need to specify a value for this property, use the static field Cache.NoSlidingExpiration.

  • priority Enables you to specify the priority of the cached item. Possible values are AboveNormal, BelowNormal, Default, High, Low, Normal, and NotRemovable.

  • onRemoveCallback Enables you to specify a method that is called automatically before the item is removed from the cache.

When using the cache, it is important to understand that items that you add to the cache might not be there when you attempt to retrieve the item in the future. The cache supports scavenging. When memory resources become low, items are automatically evicted from the cache.

Before using any item that you retrieve from the cache, you should always check whether the item is Nothing (null). If an item has been removed, then you'll retrieve Nothing when you attempt to retrieve it from the cache in the future.

You can add almost any object to the cache. For example, you can add custom components, DataSets, DataTables, ArrayLists, and Lists to the cache.

You shouldn't add items to the cache that depend on an external resource. For example, it does not make sense to add a SqlDataReader or a FileStream to the cache. When using a SqlDataReader, you need to copy the contents of the SqlDataReader into a static representation such as an ArrayList or List collection.

Adding Items with an Absolute Expiration Policy

When you insert items in the cache, you can specify a time when the item will expire. If you want an item to remain in the cache for an extended period of time, then you should always specify an expiration time for the item.

The page in Listing 23.36 illustrates how you can add an item to the cache with an absolute expiration policy. The item is added to the cache for one hour.

Listing 23.36. ShowAbsoluteExpiration.aspx

[View full width]

<%@ Page Language="VB" Trace="true" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <%@ Import Namespace="System.Web.Configuration" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> Private Sub Page_Load() ' Get movies from Cache Dim movies As DataTable = CType(Cache("Movies"), DataTable) ' If movies not in cache, recreate movies If IsNothing(movies) Then movies = GetMoviesFromDB() Cache.Insert("Movies", movies, Nothing, DateTime.Now.AddHours(1), Cache .NoSlidingExpiration) End If grdMovies.DataSource = movies grdMovies.DataBind() End Sub Private Function GetMoviesFromDB() As DataTable Trace.Warn("Getting movies from database") Dim conString As String = WebConfigurationManager.ConnectionStrings("Movies") .ConnectionString Dim dad As New SqlDataAdapter("SELECT Title,Director FROM Movies", conString) Dim movies As New DataTable() dad.Fill(movies) Return movies End Function </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Show Absolute Expiration</title> </head> <body> <form runat="server"> <div> <asp:GridView Runat="server" /> </div> </form> </body> </html>

The first time the page in Listing 23.36 is requested, nothing is retrieved from the cache. In that case, a new DataTable is created that represents the Movies database table. The DataTable is inserted into the cache. The next time the page is requested, the DataTable can be retrieved from the cache and there is no need to access the database.

The DataTable will remain in the cache for one hour, or until memory pressures force the DataTable to be evicted from the cache. In either case, the logic of the page dictates that the DataTable will be added back to the cache when the page is next requested.

Tracing is enabled for the page in Listing 23.36 so that you can see when the Movies database table is loaded from the cache and when the table is loaded from the database. The GetMoviesFromDB() method writes a trace message whenever it executes (see Figure 23.14).

Figure 23.14. Adding an item to the cache with an absolute expiration policy.

Adding Items with a Sliding Expiration Policy

When you specify a sliding expiration policy, items remain in the cache just as long as they continue to be requested within a specified interval of time. For example, if you specify a sliding expiration policy of 5 minutes, then the item remains in the Cache just as long as no more than 5 minutes pass without the item being requested.

Using a sliding expiration policy makes sense when you have too many items to add to the cache. A sliding expiration policy keeps the most requested items in memory and the remaining items are dropped from memory automatically.

The page in Listing 23.37 illustrates how you can add a DataSet to the cache with a sliding expiration policy of 5 minutes.

Listing 23.37. ShowSlidingExpiration.aspx

[View full width]

<%@ Page Language="VB" Trace="true" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <%@ Import Namespace="System.Web.Configuration" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> Private Sub Page_Load() ' Get movies from Cache Dim movies As DataSet = CType(Cache("Movies"), DataSet) ' If movies not in cache, re-create movies If IsNothing(movies) Then movies = GetMoviesFromDB() Cache.Insert("Movies", movies, Nothing, Cache.NoAbsoluteExpiration, TimeSpan .FromMinutes(5)) End If grdMovies.DataSource = movies grdMovies.DataBind() End Sub Private Function GetMoviesFromDB() As DataSet Trace.Warn("Getting movies from database") Dim conString As String = WebConfigurationManager.ConnectionStrings("Movies") .ConnectionString Dim dad As New SqlDataAdapter("SELECT Title,Director FROM Movies", conString) Dim movies As New DataSet() dad.Fill(movies) Return movies End Function </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Show Sliding Expiration</title> </head> <body> <form runat="server"> <div> <asp:GridView Runat="server" /> </div> </form> </body> </html>

In Listing 23.37, when the DataSet is added to the cache with the Insert() method, its absoluteExpiration parameter is set to the value Cache.NoAbsoluteExpiration and its slidingExpiration parameter is set to an interval of 5 minutes.

Adding Items with Dependencies

When you add an item to the Cache object, you can make the item dependent on an external object. If the external object is modified, then the item is automatically dropped from the cache.

The ASP.NET Framework includes three cache dependency classes:

  • CacheDependency Enables you to create a dependency on a file or other cache key.

  • SqlCacheDependency Enables you to create a dependency on a Microsoft SQL Server database table or the result of a SQL Server 2005 query.

  • AggregateCacheDependency Enables you to create a dependency using multiple CacheDependency objects. For example, you can combine file and SQL dependencies with this object.

The CacheDependency class is the base class. The other two classes derive from this class. The CacheDependency class supports the following properties:

  • HasChanged Enables you to detect when the dependency object has changed.

  • UtcLastModified Enables you to retrieve the time when the dependency object last changed.

The CacheDependency object also supports the following method:

  • GetUniqueID Enables you to retrieve a unique identifier for the dependency object.

Note

You can create a custom cache dependency class by deriving a new class from the base CacheDependency class.

The SqlCacheDependency class is discussed in detail in the final section of this chapter. In this section, I want to show you how you can use the base CacheDependency class to create a file dependency on an XML file.

The page in Listing 23.38 creates a dependency on an XML file named Movies.xml. If you modify the Movies.xml file, the cache is reloaded with the modified file automatically.

Listing 23.38. ShowFileDependency.aspx

<%@ Page Language="VB" Trace="true" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> Private Sub Page_Load() Dim movies As DataSet = CType(Cache("Movies"), DataSet) If IsNothing(movies) Then Trace.Warn("Retrieving movies from file system") movies = New DataSet() movies.ReadXml(MapPath("~/Movies.xml")) Dim fileDepend As New CacheDependency(MapPath("~/Movies.xml")) Cache.Insert("Movies", movies, fileDepend) End If grdMovies.DataSource = movies grdMovies.DataBind() End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Show File Dependency</title> </head> <body> <form runat="server"> <div> <asp:GridView Runat="server" /> </div> </form> </body> </html>

Specifying Cache Item Priorities

When you add an item to the Cache, you can specify a particular priority for the item. Specifying a priority provides you with some control over when an item gets evicted from the Cache. For example, you can indicate that one cached item is more important than other cache items so that when memory resources become low, the important item is not evicted as quickly as other items.

You can specify any of the following values of the CacheItemPriority enumeration to indicate the priority of a cached item:

  • AboveNormal

  • BelowNormal

  • Default

  • High

  • Low

  • Normal

  • NotRemovable

For example, the following line of code adds an item to the cache with a maximum absolute expiration time and a cache item priority of NotRemovable:

[View full width]

Cache.Insert("ImportantItem", DateTime.Now, Nothing, DateTime.MaxValue, Cache .NoSlidingExpiration, CacheItemPriority.NotRemovable, Nothing)

Configuring the Cache

You can configure the size of the cache by using the web configuration file. You specify cache settings with the cache element. This element supports the following attributes:

  • disableMemoryCollection Enables you to prevent items from being removed from the cache when memory resources become low.

  • disableExpiration Enables you to prevent items from being removed from the cache when the items expire.

  • privateBytesLimit Enables you to specify the total amount of memory that can be consumed by your application and its cache before items are removed.

  • percentagePhysicalMemoryUsedLimit Enables you to specify the total percentage of memory that can be consumed by your application and its cache before items are removed.

  • privateBytesPollTime Enables you to specify the time interval for checking the application's memory usage.

Notice that you can't set the size of the cache directly. However, you can specify limits on the overall memory that your application consumes, which indirectly limits the size of the cache.

By default, both the privateBytesLimit and percentPhysicalMemoryUsedLimit attributes have the value 0, which indicates that the ASP.NET Framework should determine the correct values for these attributes automatically.

The web configuration file in Listing 23.39 changes the memory limit of your application to 100,000 kilobytes and disables the expiration of items in the cache.

Listing 23.39. Web.Config

<?xml version="1.0"?> <configuration> <system.web> <caching> <cache privateBytesLimit="100000" disableExpiration="true"/> </caching> </system.web> </configuration>

The page in Listing 23.40 displays your application's current private bytes limit (see Figure 23.15):

Figure 23.15. Displaying the maximum application and cache size.

Listing 23.40. ShowPrivateBytesLimit.aspx

<%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> Sub Page_Load() lblPrivateBytes.Text = Cache.EffectivePrivateBytesLimit.ToString("n0") End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Show Private Bytes Limit</title> </head> <body> <form runat="server"> <div> Effective Private Bytes Limit: <asp:Label Runat="server" /> </div> </form> </body> </html>

Категории