Introduction
This tip will explain approaches to improve an ASP.NET Web application's performance. Application's performance is an important requirement/consideration while designing any application especially when there are going to be 100s and 1000s of requests coming through every second. This tip will introduce some of the ASP.NET framework provided features to help enhance application's performance.
Background
In general, an application’s performance can be improved by saving frequently retrieved data in memory especially when the data was generated as a result of complex programming logic and retrieved from a database or from a file. Saving the retrieved data in memory and displaying the in memory data during successive requests instead of re-performing the complex logic, would enormously improve application’s performance and as well the user experience. For this purpose, ASP.NET framework provides two basic caching mechanisms:
Application Caching
Output Caching
In this tip, we will see how performance can be improved through application caching. In my next article, we will discuss about Output Caching and its advantages.
Application Caching
Application caching can be implemented using ASP.NET’s
Cache
class. This class belongs to
System.Web.Caching
namespace.
Cache items added to the
Cache
object are
private
to each application, similar to application state values. Its lifetime is dependent on the application itself, so if the application restarts, the
Cache
objects will get re-created.
It is very easy to use this
Cache
class. We will now see how we can add and retrieve items to
Cache
object and thereby improve application’s performance.
Adding Items to Cache
Only one instance of this
Cache
object is created for each application domain, and it remains valid as long as the application is active. This object can be accessed either through the
HttpContext
object or the
Cache
property of the
Page
object.
Cache
object is a key value pair collection and items can be added to
Cache
in three different ways:
1. Setting the Cache Item Via Key and a Value
Cache[
"
Key1"
] =
"
Value1"
;
The above statement has added an item called “
Key1
”to the
Cache
object and its value has been set to “
Value1
”. The above example sets the cache item “
Key1
” with a
string
, but it can be of any object type.
2. Using the Insert Method
The
Insert
method has 5 overloaded versions.
Let us see an example of retrieving data from an XML file and caching this data unless the file’s content is altered. Let us assume that we have the following weather related data in an XML file:
="
1.0"
="
utf-8"
<
ArrayOfObservation
>
<
Observation
>
<
Station
>
Liverpool
<
/Station
>
<
DateTime
>
2010-09-01T00:00:00
<
/DateTime
>
<
Temparature
>
28.52944896953
<
/Temparature
>
<
/Observation
>
<
Observation
>
<
Station
>
Holsworthy
<
/Station
>
<
DateTime
>
2010-09-01T00:00:00
<
/DateTime
>
<
Temparature
>
30.68702763071
<
/Temparature
>
<
/Observation
>
<
Observation
>
<
Station
>
ChippingNorton
<
/Station
>
<
DateTime
>
2010-09-01T00:00:00
<
/DateTime
>
<
Temparature
>
29.52944896953
<
/Temparature
>
<
/Observation
>
<
Observation
>
<
Station
>
Padstow
<
/Station
>
<
DateTime
>
2010-09-01T00:00:00
<
/DateTime
>
<
Temparature
>
31.68702763071
<
/Temparature
>
<
/Observation
>
<
/ArrayOfObservation
>
To keep it simple, the above file contains weather data for just 4 different suburbs, each record contains Station Name, DateTime and the Temparature details. Let us assume that we would like to present this data in a grid view. Once the data is read from the file, we can data bind it to a
GridView
control. This data might get updated few times during the day. Instead of reading from the XML file every time a user requests for this data, we could cache the data in the Application’s
Cache
object and can invalidate it and repopulate it only if the contents of the file have been updated. The following code snippet shows how to use this type of File Dependency:
private
void
LoadWeatherData()
if
(Cache[
"
WeatherData"
] ==
null
)
DataSet ds =
new
DataSet();
string
weatherDataFile =
HttpContext.Current.Server.MapPath (
@"
~\data\WeatherData.xml"
);
ds.ReadXml(weatherDataFile);
GridView1.DataSource = ds;
GridView1.DataBind();
CacheDependency cd =
new
CacheDependency(weatherDataFile);
Cache.Insert(
"
WeatherData"
, ds, cd);
GridView1.DataSource = (DataSet)Cache.Get(
"
WeatherData"
);
GridView1.DataBind();
Once the item is cached, until, the contents of the file are updated, or the .NET Framework decides to remove the item from the Cache for reasons like low memory, or if the user has explicitly removed the item from the cache, every request to this data will be retrieved from the Cache. Whenever the data in the XML file is updated or the item is removed from the Cache, then the
LoadWeatherData
method will read from the file and add the item again to the Cache. Though the above example doesn’t involve any complex logic, in places where we might need complex business logic to be used on the data read from the file before presenting it to the user, the caching mechanism would eliminate the reprocessing of the data and would help presenting the data straight from the cache and thus would significantly improve performance.
Note
: The above example uses
CacheDependency
on a file to update the Cache. If the data is retrieved from a database, then we could use
SqlCacheDependency
mechanism to enable
Cache
item to be updated when the underlying data table gets updated. We will discuss about this in my future article.
There is another overloaded version of this
Insert
method which takes a delegate as a parameter (
CacheItemRemovedCallback
), which gets notified, when the cached data is removed from the
Cache
object.
The following code snippet shows how the
CacheItemRemovedCallback
delegate can be used: (The signature of this delegate can be checked from Visual Studio by highlighting this class name and using the “Go To Definition” option from the context menu popup).
The above code checks whether an item called “
WeatherData
” exists in the
Cache
object. If it doesn’t exist, then it reads from the XML file and binds the data to the
GridView
Controller and it also adds the item to the
Cache
collection. Else it simply binds the data in the
Cache
object to the
GridView
Controller.
private
void
LoadWeatherData()
DataSet ds =
new
DataSet();
string
weatherDataFile = HttpContext.Current.Server.MapPath(
@"
~\data\WeatherData.xml"
);
ds.ReadXml(weatherDataFile);
GridView1.DataSource = ds;
GridView1.DataBind();
CacheDependency cd =
new
CacheDependency(weatherDataFile);
System.Web.Caching.CacheItemRemovedCallback cacheItemRemovedCallback =
new
CacheItemRemovedCallback (onCacheItemRemoved);
Cache.Insert(
"
WeatherData"
, ds,
null
, System.DateTime.Now.AddSeconds(
60
),
System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Default,
cacheItemRemovedCallback);
public
void
onCacheItemRemoved(
string
key,
object
value
, CacheItemRemovedReason reason)
In addition to the above
Insert
methods, there are few simple overloaded versions which can be used to either set an absolute expiration time, or a sliding expiration time. Note, both absolute and sliding expiration options can’t be used at the same time.
The following example shows how the inserted item can be cached for a minute using absolute expiration:
HttpContext.Current.Cache.Insert(
"
WeatherData"
, ds,
null
,
DateTime.Now.AddSeconds(
60
),
System.Web.Caching.Cache.NoSlidingExpiration);
The above statement will remove the
Cache
item “
WeatherData
” from the cache after 1 minute. If we want to set a sliding expiration, then the Absolute expiration
should be set to
System.Web.Caching.Cache.NoAbsoluteExpiration
as shown below:
HttpContext.Current.Cache.Insert(
"
WeatherData "
, ds,
null
,
System.Web.Caching.Cache.NoAbsoluteExpiration,
new
TimeSpan(
0
,
5
,
0
));
Though we can
Cache
items in the
HttpContext.Current.Cache
object, it is not always guaranteed that the
Cache
item will remain in the
Cache
object for the predefined time. If the application’s memory is running low, then the .NET framework could decide to remove some of the Cached items. The Cached items can be set with a priority value as shown in the following example:
HttpContext.Current.Cache.Insert(
"
WeatherData"
,
ds,
null
, System.Web.Caching.Cache.NoAbsoluteExpiration,
new
TimeSpan(
0
,
5
,
0
),
System.Web.Caching.CacheItemPriority.NotRemovable,
null
);
When the priority is set to
NotRemovable
, then this item will not be removed from the
Cache
as compared to others even under circumstances where .NET framework decides to remove one or more items from the
Cache
. But if the
Cache
item had an expiry time set or if it is dependent on another
Cache
or file, then it will be removed under such circumstances. The other possible priority values are:
Low
,
Normal
,
BelowNormal
,
AboveNormal
,
High
,
Default
.
3. Using the Add Method
The
Add
method can also be used instead of
Insert
method and the
Add
method also takes all of the above parameters, but there are no overloaded methods which take less parameter as compared to
Insert
method. As well, the
Add
method will return an instance of the added
Cache
object whereas the
Insert
method wouldn’t. Removing Items from
Cache
to remove or delete an item from the
Cache
explicitly, we can use
Remove
method as follows:
Cache.Remove(
"
WeatherData"
);
The above method would remove the
Cache
item “
WeatherData
” from the
Cache
permanently.
License
Hi $andhesh,
Application Data gets Cached in web server, where as Page Output Caching can be configured to get saved either in the Web server, or at the client browser or in the downstream resources like proxy servers.
Absolute expiration can be used if we wish to invalidate or remove the cached item from the memory after a specific duration of time. For instance we could use the following code to remove the cached item after 2 minutes from the cache (since it was added) whether it has been used or not.
Cache.Insert(
"
WeatherData"
, ds,
null
, System.DateTime.UtcNow.AddSeconds(
120
), System.Web.Caching.Cache.NoSlidingExpiration)
But Sliding expiration will allow the cached item to stay in the cache as long as the item has been accessed within the duration specified. And after each access the cached item's sliding expiration is renewed to its original duration. For instance if we have set the sliding expiration to 5 minutes, if it was accessed at least once within that 5 minutes period, then its expiration will be reset to 5 minutes again. So as long as this item is being used within 5 minutes, each access will reset the time to another 5 minutes since its last access. That's why sliding expiration becomes handy for frequently retrieved items. But if the cached item was not accessed within 5 minutes, it will also be removed from the cache.
Hope it makes sense.
Thanks,
Latha
Sign In
·
View Thread
Member 10221604 wrote:
Application Data gets Cached in web server, where as Page Output Caching can be configured to get saved either in the Web server, or at the client browser or in the downstream resources like proxy servers.
Thanks for reply. If we add this in your article that will be good. One more question, how we configure Output caching to store cache data on Web server, or at the client browser or in the downstream resources like proxy servers.
+5 from my side.
Cheers,
SMP
My Recent Article
Main Method in C#
Sign In
·
View Thread
Hi $andesh,
Thanks for your comments. OutputCaching is achieved using the @ OutputCache directive of the .aspx page as follows:
<%@ OutputCache Duration="#ofseconds"
Location="Any | Client | Downstream | Server | None | ServerAndClient "
VaryByParam="parametername" %>
The Location attribute is used to decide where exactly we want to save the Cached Items. The default is "Any"
The OutputCache Direcitve has several other attributes, but Duration and VaryByParam are the only required attributes.
Thanks,
Latha
Latha Elangovan
Sign In
·
View Thread
Web01
2.8:2023-07-24:2