Caching is an important part of web technology. The success of any web application is based on two major factors, Security and web applications performance. In this article we will try to look into increasing application performance by means of caching. This article focuses on caching in ASP.NET web application. When Caching is applied to ASP.NET web application, it greatly enhance the performance of Web applications. With .NET we have the ability to cache whole pages (output caching), parts of pages or server controls (fragment caching) and data caching with the lower-level Cache.
What is Caching ?
Caching means temporary storage of data in memory that is highly-demanding and frequently used in order to accelerate performance and for quick access to various essential information.
Why Caching ?
One of the very common items stored in cache in any web application is commonly used database values, caching in this situation give a greater advantage as it reduces repeated calls to the database for information. This means that reduced usage web server and database resources, giving greater advantage on scalability of the web application.
NET Framework provides various ways to handle caching of data. There are three main ways of achieving the same namely page level output caching, user control level output caching (or fragment caching), and the Cache API. In these three option output caching and fragment caching are simple to implement and usually solves most of the requirement in many cases. Cache API provides additional advantage of caching throughout every layer of an application.
Lets take each of this type of caching in details in the following section
Page Level Output Caching:
This is the most simplest form of caching. caches the output of a page (or portions of it) so that content of page are not generated every time it is loaded. In this case the subsequent request are severed with the cached out until cache expires. This give a great performance increase of web application.
To use Page Level Output Caching following directive has to be used in ASP.NET page.
Syntax: <%@ OutputCache Duration=”n seconds” VaryByParam=”none” %> |
There are five in all five parameters that the above directive takes and amongst them two are mandatory parameters:
Duration: This is a mandatory parameter and has value as Time, in seconds (always positive). This is the amount of time should be cached.
VaryByParam: This is a mandatory parameter. This is used to mention whether variables in the request should result in separate cache entries. It takes values namely “none” or “*”.”none” can be used to specify no separate cache requirement. “*” indicates create a new cache entires for different set of variables. All the variables to be cached are specified separated with”;”
Example of Page Level Output Caching using above two parameter
a) <%@ OutputCache Duration=”60″ VaryByParam=”none” %> |
Explanation: the page will be cached for a duration of 60 second and then it will expire. VaryByParam=”none” indicates that there will be single cached page available for this duration specified.
b) <%@ OutputCache Duration=”60″ VaryByParam=”UserID;Name” %> |
Explanation: The page will be cached for a duration of 60 second and then it will expire. VaryByParam=”UserID;Name” indicates that page will be cached according to the userid and name variation and will be available for this duration specified.
Location: This is place where the page/output should be cached. It can take values namely Any, Client, Downstream, None, Server or ServerAndClient
Example of Page Level Output Caching using above parameters
<%@ OutputCache Duration=”60″ VaryByParam=”none” Location=”ServerAndClient”%> |
Explanation: The page will be cached for a duration of 60 second and then it will expire. VaryByParam=” none” indicates that page will be cached according to the userid and name variation and will be available for this duration specified. Location=”ServerAndClient” indicates page will be cached both at Server and client
VaryByHeader: This is used to vary cache entries based on specified header.
VaryByCustom This is used to vary cache based on specified entries in the global.asax
VaryByHeader and VaryByCustom are primarily used to customise look and feel of the on the client accessing site. Apt example might be that same URL cached with different look and feel for different browser on same machine
Example of Page Level Output Caching using above parameters
<%@ OutputCache Duration=”60″ VaryByParam=”None” VaryByCustom=”browser” %> |
Explanation: The page will be cached for a duration of 60 second and then it will expire. VaryByParam=” none” indicates that there will be single cached page available for this duration specified. VaryByCustom=”browser” indicates that page will be cached on the bases of browser specification.
Fragment Caching, User Control Output Caching
While Page Level Output Caching is useful when most of the content of the page doesn’t change often, In case where only specific part of page content changes we don’t need to cache entire page instead we can cache parts that are constant across each and every scenario. Thus a much more powerful and flexible application allows to cache individual objects in your Web application rather then entire application. Some of the examples of such parts might be Menus and other layout elements and especially when menus are dynamically generated from a data source.
Fragment caching uses the same syntax as page level output caching, but applied to a user control (.ascx file) instead of to a web form (.aspx file). All of the attributes that are supported by the OutputCache directive on a web form are also supported for user controls except that Location attribute is not allowed at this type of caching. In User controls has one more OutputCache attribute called VaryByControl, which will vary the caching of the user control depending on the value of a member of that control (typically a control on the page, such as a DropDownList). Here important point that needs to be remembered is if VaryByControl is specified for a control then VaryByParam can be omitted.
In ASP.NET each user control is cached separately and this is a default setting if not specified. However, if a user control does not vary between pages in an application and the control name is same across the pages then by specifying Shared=”true” will allow the cached version of the user controls by all the pages instead of keeping a separate cache for each one of the same user control.
User control caching can be achieved by following directive that needs to be added in .ascx file so that the user control can be cached.
Syntax: <%@ OutputCache Duration=”n Second” VaryByControl=”<Sting Constant>” %> |
Example of Fragment Caching, User Control Output Caching
a) <%@ OutputCache Duration=”60″ VaryByParam=”*” %> |
Explanation: This would cache the user control for 60 seconds, also create a separate cache entry for every new querystring variable values . This control will be cached for every page where this control is placed on.
b) <%@ OutputCache Duration=”60″ VaryByParam=”none” VaryByControl=”CountryDropListBox” %> |
Explanation: This would cache the user control for 60 seconds. Here main point to note is that a separate cache entry will be created for each of different value of the CountryDropListBox control also each cache entry will be made for each page where this control is placed.
c) <%@ OutputCache Duration=”60″ VaryByParam=”none” VaryByCustom=”browser” Shared=”true” %> |
Explanation: This would cache the user control for 60 seconds main difference between this and earlier example is that there will be one cache entry for each browser type and its major version. Also since Shared=”true” is specified cache entries for each browser will be shared by all the pages that are referencing the user control this means that all the pages referring same control with same ID
Caching API, Caching using Cache Object
Application Level Caching While output caching is useful, a much more powerful and flexible application would be to cache individual objects in your Web application. The cache objects are used to store any serializeable data object with the facility to specify the cache expiry based on any dependencies this means create a cache objects and associate with it a dependency like duration for the cached variable, time since the variable was accessed etc We can use the Cache object share the same objects across the related pages.
There are main cases when web application refers to master information, like referring to master look up tables for information, if a repeated call is made Database to get these information, this will impact the performance of web application. This a very apt situation where we can make use of caching the objects and keep referring it as and when required when and refresh the cache when there are any changes and this is achieved by cache dependencies.
In .NET data caching is main done using two classes in System.Web. Caching namespace namely “Cache” and “CacheDependency”. “Cache” object is used to add or remove cached objects from the cache. CacheDependency is used to specify the dependencies to cached objects. Let see how this can be achieved in the following section
Add and item to cache: To add an object in cache following syntax is used
Syntax: Cache[“key”] = value: |
Explanation: Using the above syntax we can store the item in the cache. This entry will have no dependencies on it. Dependencies like it will not expire unless the cache engine removes it.
Referencing / retrieving the Cached object: Once the object is added, to reference this object we need to use the name of cached object i.e. the key of the cached object. This achieved using the following syntax:
Syntax: value = Cache.Get(“key”); |
Explanation: The above syntax is used to retrieve the value form cache
Removing cached object: Following syntax is used to remove value from cache:
Syntax: Cache.Remove(“key”); |
Explanation: Above statement will remove the key cached object from cache
Adding dependencies to cached objects: To include cache dependencies, the Add() or Insert() method is used. These methods have several overload methods depending on the parameters set. The only difference between Add() and Insert() is that Add() returns a reference to the cached object, while has no return value i.e. it is a void function. Following are the overloaded methods that can be used:
a) Syntax: Insert(key as String, value as Object) – This is the most simplest form of Inserts methods. This caches object value into the cache, and is referenced by the name key. This is semantically equivalent to using Cache(“key”) = value .
b) Syntax: Insert(key as String, value as Object, dependencies as CacheDependency) – This caches object value into the cache, references it by the name key and dependencies specified by the dependencies parameter.
What is CacheDependency? Cache uses system resources so sometime it is required to focus on data beginning cached and the way it is cached. By specifying CacheDependency we can achieve the required. To specify the cache dependency on the object, use the System.Web.Caching.CacheDependency class.
Example: Cache.Insert(“key”, XMLFileData, new System.Web.Caching.CacheDependency(Server.MapPath(“XMLFileData.xml”))); |
Explanation: In the above example insert XMLFileData.xml data from a file is put into cache, thus making subsequent requests to read the information from cache. The CacheDependency will ensure that when the file changes, the cache will immediately expire, allowing the latest data to be pulled from the file and re-cached. An array of filenames can also be specified if the cached data depends on several files.
c) Time-Based Caching: We can specify time dependencies on a cached object, this will make the cached object to expire on certain time depending on the dependence. This can be achieved in following two manner
– Absolute Expiration. The cache is set to expire on a particular date and time.
– Sliding Expiration. The cache is set to expire after a certain period of inactivity. The above two can be achieved with the overloaded methods of insert as mentioned below
Absolute Expiration:
Syntax: Insert(key as String, value as Object, dependencies as CacheDependency, absoluteExpiration as DateTime, slidingExpiration as TimeSpan) |
This Inserts the object value into the cache with key name key , with dependencies “dependencies”, and (time-based) expiration policies.
Example : Cache.Insert(“key”, DataAccessCachedValue, null, DateTime.Now.AddMinutes(1), TimeSpan.Zero); |
Explanation: This example will cache the time sensitive data for one minute, at which point the cache will expire.
Sliding Expiration: The data will remain in the cache until given amount of time duration is passed and the cached object is not referenced at all.
Syntax: Insert(key as String, value as Object, dependencies as CacheDependency, absoluteExpiration as DateTime, slidingExpiration as TimeSpan)
Example: Cache.Insert(“key”, DataAccessCachedValue, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(10)); |
Explanation: In the above example data will remain in the cache until ten minute and without anything referencing it.
# Note that absolute expiration and sliding expiration (below) cannot be used together.
d) Syntax: Insert(key as String, value as Object, dependencies as CacheDependency, absoluteExpiration as DateTime, slidingExpiration as TimeSpan, priority as CacheItemPriority, onRemoveCallBack as CacheItemRemovedCallback)
The above statement is used to inserts the object value into the cache with key name key, dependencies dependencies , depends on the expiration policies, a cache priority, and a callback delegate. The priority specifies how important it is for the cache item to remain in the cache. That is, items with a lower priority will be evicted from the cache before items with a higher priority. The callback delegate provides a means for you to create your own function that is automatically called when the item is evicted from the cache.
What is the CacheItemPriority? This property specifies the priority in which the cached objects need to be placed low to high to NotRemovable and this can be defined with the with object System.Web.Caching.CacheItemPriority enumeration
What is CacheItemRemovedReason ? This property is used to specify how the cached objects need to be removed from the cached. The property can take following values
DependencyChanged – the cached entry will be removed from the cache when there a change in dependencies vales.
Expired – This time based expires.
Removed – When the cached entries are explicitly removed in this case by the Remove method.
Underused – This is used to specify that when system is under resource it can remove the mentioned cached objects to free resources
Example:
System.Web.Caching.CacheItemRemovedCallback callback = new System.Web.Caching.CacheItemRemovedCallback (OnRemove);
Cache.Insert(“key”,DataAccessFile,null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Default, callback); public static void OnRemove (string key, object CachedObjects, System.Web.Caching.CacheItemRemovedReason Caption) { Console.write (“Cached Object : ‘” + key ); Console.write (“Taken out of Cache Reason: ” + Caption.ToString()); } |
Explanation: In above example when the cached object is removed there will be message printed on console displaying the message (Caption).
Conclusion: This article gives insight of the importance of caching in web application used in ASP.NET and C#. As we have seen caching has huge performance benefits to applications. Caching gives web pages an effective way to increase performance while minimizing the use of server resources. There can be always a trade of between the items that can be cached and server resource usages