|
Developers often need to temporarily put data (temporary data) in a storage medium (for example, a database or some location in memory) for quick access. The storage of this temporary data is called a cache. A cache provides a number of possibilities. For example, imagine that you're working with a database in which data will be changed very rarely. When a user requests data, you will retrieve the same data each time from the database. Each time, the server will process the same operation to the retrieve the data and the performance of the application will be decreased. The best solution in such a situation is to store retrieved data in storage (at least for a short period of time). After storing the data, you can read it directly from the cache. In the cache, you could store database data as well as whole HTML pagesit depends on the logic of the application being implemented. Experience in web application development will teach you that developers often store data retrieved from a database in static variables (static hash tables, arrays, and so on), but do not often store HTML pages on the server side with help of ASP.NET's cache toolkit. But ASP.NET's mechanism of caching is very powerful and helpful (especially in small web applications). All cached data is stored in memory so that it can be retrieved and processed significantly faster than if it were stored on magnetic media such as a hard disk. If a developer uses the cache correctly, he can greatly increase the performance of his application. ASP.NET presents simple and very powerful possibilities of working with data caching. It enables you to cache whole HTML pages (or just parts of them) and other data in the global object HttpCache. Introduction to ASP.NET CachingThe code in Listing 24.1 is a simple example that shows how to use a cache in ASP.NET. Listing 24.1. Caching HTML Pages by Using the OutputCache Directive<%@ Page language="c#" Codebehind="Main.aspx.cs" AutoEventWireup="false" Inherits="OutputCacheSample.Main" %> <%@ OutputCache Duration="60" VaryByParam="none"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <html> <head> <title>OutputCache using Sample</title> <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1"> <meta name="CODE_LANGUAGE" Content="C#"> <meta name=vs_defaultClientScript content="JavaScript"> <meta name=vs_ targetSchema content="http://schemas.microsoft.com/intellisense/ie5"> </head> <body MS_POSITIONING="GridLayout"> <table cellpadding="0" cellspacing="0" border="0"> <tr> <td> Page's invocation time: </td> <td> <%=DateTime.Now.ToString("F")%> </td> </tr> </table> </body> </html> This example simply outputs the server's time on a web page. When the page first appears, it is cached because of the OutputCache directive in the second line of Listing 24.1. The page will be stored in the cache for 60 seconds. If a user requests this page, his browser will show the cached page with the old time. After the cache has been cleared, the user can view the updated page. We have two ways to cache HTML pages:
OutputCache and HttpCachePolicy are very similar, but using OutputCache is more user friendly. The following section discusses how to use the OutputCache directive in detail. OutputCache DirectiveListing 24.1 showed how to use the OutputCache directive to quickly retrieve HTML pages from the cache. That example is very simple because it uses just one attribute from the available set of predefined parameters of the OutputCache directive. It uses the parameter Duration, which declares the time (in seconds) that pages should be stored in the cache. The example also declares that the page will have just one cached version, independent of the set of parameters of this one. The OutputCache directive has the following attributes: <%@ OutputCache Duration="value" Location="value" VaryByParam="value" VaryByHeader="value" VaryByCustom="value" %> The following list describes each attribute in more detail:
To use the Location attribute in OutputCache, you should change the second line in Listing 24.1 to the following: <%@ OutputCache Duration="60" VaryByParam="none" Location="Server"%> In this case, the page will be cached for 60 seconds only on the server side. TIP Note that different values of the Location attribute will cause different behavior by the application. You should use it very carefully, taking into account the settings of the server and client browsers.
Using HttpCachePolicyAs mentioned earlier, ASP.NET provides two ways to cache HTML pages. The first approachthe OutputCache directivewas discussed earlier. So, the following section covers the second approach: the HttpCachePolicy class. To be more precise, the OutputCache directive is just an intuitive interface of the HttpCachePolicy class. But OutputCache gives more limited possibilities than HttpCachePolicy. For example, you aren't allowed to set an absolute expiration time for storing an object in the cache with the help of OutputCache, but HttpCachePolicy allows you to do so. You could retrieve access to that object via the Response.Cache object represented in ASP.NET. Listing 24.2 is an example that shows the simplest way of using HttpCachePolicy. (The ASPX representation of this example is the same as in Listing 24.1, but without the use of the OutputCache directive.) Listing 24.2. Caching HTML Pages by Using the HttpCachePolicy Classusing System; using System.Collections; using System.ComponentModel; using System.Data; using System.Drawing; using System.Web; using System.Web.SessionState; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; namespace HttpCachePolicySample { public class Main : System.Web.UI.Page { private void Page_Load(object sender, System.EventArgs e) { Response.Cache.SetCacheability(HttpCacheability.Server); Response.Cache.SetExpires(DateTime.Now.AddSeconds(60)); } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { InitializeComponent(); base.OnInit(e); } private void InitializeComponent() { this.Load += new System.EventHandler(this.Page_Load); } #endregion } } This example caches the page by using two methods of the HttpCachePolicy class: SetExpires and SetCacheability. In this case, the page will be cached on the server side for 60 seconds. You could also use the HttpCacheability.Public enumeration member for caching page anywhere (doing so is the same as using the Any value for the OutputCache.Location attribute). TIP Note that this article doesn't describe all the members and methods of the HttpCachePolicy class in detail. You can find all necessary information about them on any website related to ASP.NET technology and on Microsoft's MSDN site. In this chapter, we review only the most demonstrative methods of the class. The SetExpires method helps to set an absolute expiration time for a page in the cache. The example in Listing 24.2 shows how to use SetExpires in tandem with the DateTime class. You are also allowed to use it in the following way: Response.Cache.SetExpires(DateTime.Now.AddSeconds(60)); Response.Cache.SetExpires(DateTime.Parse("04:00")); In this case, the page will be deleted from the cache at 4 o'clock local time. Both methods that have been discussed enable you to set an absolute expiration time. But there is one more ASP.NET method that enables you to set the caching type to a sliding mode: Response.Cache.SetSlidingExpiration( true ); When you use absolute caching, the page is stored in the cache until a particular amount of time expires, without taking into account the quantity of requests that have been performed to this page. When you use a sliding expiration, the page will be deleted from cache only when the page has not been requested by any user for a certain length of time (in the sample case, it's 60 seconds). If a user requests the page during that length of time, the page will again be stored in the cache for an interval equal to the previous one. Using the Cache ObjectThere is another class in ASP.NET that enables you to cache data. This class is called Cache, and you get access to it via the Cache property of the current context of the web application (for example, Context.Cache). This object enables you to both store data and to retrieve stored data. It also supports the following:
Listing 24.3 shows how to use the Cache object. This example puts some data into the cache and shows that data in the browser. It also checks the source from which the data has been retrieved. Listing 24.3. Using the Cache Object (Code-Behind)using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Drawing; using System.Web; using System.Web.SessionState; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; namespace CacheSample { public class Main : System.Web.UI.Page { protected HtmlTableCell DataCell; protected HtmlTableCell SourceCell; private void Page_Load(object sender, System.EventArgs e) { String data = "Some data that should be cached."; String source = ""; if (Cache[SOME_DATA_KEY] != null) { data = Cache[SOME_DATA_KEY].ToString(); source = "Cache"; } else { Cache[SOME_DATA_KEY] = data; source = "Not Cache"; } DataCell.InnerText = data; SourceCell.InnerText = source; } private const string SOME_DATA_KEY = "SOME_DATA_KEY"; #region Web Form Designer generated code override protected void OnInit(EventArgs e) { InitializeComponent(); base.OnInit(e); } private void InitializeComponent() { this.Load += new System.EventHandler(this.Page_Load); } #endregion } } Listing 24.4 shows the HTML version of this example. Listing 24.4. Using Cache Object (HTML Representation)<%@ Page language="c#" Codebehind="Main.aspx.cs" AutoEventWireup="false" Inherits="CacheSample.Main" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <html> <head> <title>Cache using Sample</title> <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1"> <meta name="CODE_LANGUAGE" Content="C#"> <meta name=vs_defaultClientScript content="JavaScript"> <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"> </head> <body MS_POSITIONING="GridLayout"> <table width="100%" cellpadding="0" cellspasing="0" border="0"> <tr> <td width="20%">Data: </td> <td runat="server" ></td> </tr> <tr> <td>Source: </td> <td runat="server" ></td> </tr> </table> </body> </html> After the first request to the page shown in Listings 24.3 and 24.4, you will see that the source of the data is Not Cache. All other requests (until the page is deleted from the cache) will return that data retrieved from the cache. TIP Note that it is mandatory to check whether an object is located in the cache; otherwise, ASP.NET will throw the exception NullReferenceException when you attempt to reference an item in the cache that does not exist. The preceding example used an implicit approach to putting objects in the cache. You also could use the following method invocation: Cache.Insert("SOME_DATA_KEY", data); The Insert method also has three additional overloads that are discussed in the upcoming sections. Assume that you've read data from a file and put it in the cache. There is some chance that file could be changed, so data in the cache also should be updated or deleted. The Cache object enables you to trace all changes in a file with data by using an additional parameter (in Cache.Insert method) with type System.Web.Caching.CacheDependency. To use this feature, you create an instance of the CacheDependency class and pass it to the Cache.Insert method: System.Web.Caching.CacheDependency dependency = new System.Web.Caching.Dependency(Server.MapPath(someFileName)); Cache.Insert(SOME_DATA_KEY, data, dependency); Before returning an object, Cache traces changes in the file that the object depends on. If the file has changed, the object is removed from Cache; otherwise, it is returned to Cache's user. The System.Web.Caching.CacheDependency class has overloads for the constructor, which enables you to trace the changes in the following:
TIP Unfortunately, due to the transient nature of instances of Page classes, there is no built-in way in ASP.NET to create a dependency that removes an item from the cache in response to changes in a DataSet. Another feature is that Cache enables you to set absolute and sliding expiration times for objects that should be inserted in it. (The differences between absolute and sliding time were discussed earlier in this chapter.) Cache.Insert("SOME_DATA_KEY", data, null, DateTime.Now.AddMinutes(5), System.Web.Caching.Cache.NoSlidingExpiration); Cache.Insert("SOME_DATA_KEY", data, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(2)); The first line shows how to use absolute object expiration time. The second line presents a sliding expiration time. TIP Notice that the System.Web.Caching.Cache.NoSlidingExpiration constant is of type System.TimeSpan, and System.Web.Caching.Cache.NoAbsoluteExpiration is of type System.DateTime. As was mentioned earlier, Cache can manage memory and automatically remove objects from memory if an overflow occurs. An algorithm for this mechanism is encapsulated in the Cache object, and you cannot review or change it, but you're allowed to exert some influence on the process. You can do this with the help of the priority parameter in the Cache.Insert method. This one is of type System.Web.Caching.CacheItemPriority. An object of lower priority will be deleted from the cache faster than objects with higher priority. You can also prohibit deletion of an object from the cache. To set an object's priority in the cache, you use the enumeration System.Web.Caching.CacheItemPriority, which has the following values: Low, BelowNormal, Default, Normal, AboveNormal, High, and NotRemovable. An object of CacheItemPriority.NotRemovable priority will not be deleted during cache clearing. The last parameter of the Cache.Insert method to be discussed is the onRemoveCallback parameter of type System.Web.Caching.CacheItemRemovedCallback. This parameter takes as its value a delegate that will be invoked during the deletion of a particular object from the cache. This allows your code to notify you about the deletion of an object from the cache. Cache.Insert("SOME_DATA_KEY", data, null, DateTime.Now.AddMinutes(5), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Low, new System.Web.Caching.CacheItemRemovedCallback(SomeDelegate)); ... ... ... private void SomeDelegate(string key, object val, System.Web.Caching.CacheItemRemovedReason reason) { ... } Cache.Remove("SOME_DATA_KEY"); TIP You could remove an object from the cache manually by using the Cache.Remove method, which requires just one parameter: key (the name of object). The final capability of the Cache object discussed in this chapter is that Cache implements the IEnumerable interface. That is why you can very simply and quickly gain access to all objects located in the Cache object. foreach(DictionaryEntry cacheEntry in Cache) { //access to key - cacheEntry.Key.ToString(); //access to value - Cache[cacheEntry.Key.ToString()].ToString(); } |
|