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:

    <? xml version =" 1.0" encoding =" 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) // Add code to inform other controls or parts of the application that the cache item has been // removed // The 3rd argument CacheItemRemovedReason is an enumerated data type indicating the // reason why, the item has been removed

    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

    This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

    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. Smile | :)
    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