ASP.NET State Management : The Application’s State

4/9/2013 4:16:10 AM
Table 1 summarizes the main features of the various state objects.
Table 1. State Management Objects at a Glance
ObjectLifetimeData VisibilityLocation
CacheImplements an automatic scavenging mechanism, and periodically clears less frequently used contentsGlobal to all sessionsDoes not support Web farm or Web garden scenarios
HttpApplicationStateCreated when the first request hits the Web server, and released when the application shuts downSame as for CacheSame as for Cache
HttpContextSpans the entire lifetime of the individual requestGlobal to the objects involved with the requestSame as for Cache
HttpSessionStateCreated when the user makes the first request, and lasts until the user closes the sessionGlobal to all requests issued by the user who started the sessionConfigurable to work on Web farms and gardens
ViewStateRepresents the calling context of each page being generatedLimited to all requests queued for the same pageConfigurable to work on Web farms and gardens

In spite of their quite unfamiliar names, the HttpApplicationState and HttpSessionState objects are state facilities totally compatible with classic Active Server Pages (ASP) intrinsic objects such as Application and Session. Ad hoc properties known as Application and Session let you use these objects in much the same way you did in ASP.

The HttpApplicationState object makes a dictionary available for storage to all request handlers invoked within an application. In classic ASP, only pages have access to the application state; this is no longer true in ASP.NET, in which all HTTP handlers and modules can store and retrieve values within the application’s dictionary. The application state is accessible only within the context of the originating application. Other applications running on the system cannot access or modify the values.

An instance of the HttpApplicationState class is created the first time a client requests any resource from within a particular virtual directory. Each running application holds its own global state object. The most common way to access application state is by means of the Application property of the Page object. Application state is not shared across either a Web farm or Web garden.

Properties of the HttpApplicationState Class

The HttpApplicationState class is sealed and inherits from a class named NameObjectCollectionBase. In practice, the HttpApplicationState class is a collection of pairs, each made of a string key and an object value. Such pairs can be accessed either using the key string or the index. Internally, the base class employs a hashtable with an initial capacity of zero that is automatically increased as required. Table 2 lists the properties of the HttpApplicationState class.

Table 2. HttpApplicationState Properties
AllKeysGets an array of strings containing all the keys of the items currently stored in the object.
ContentsGets the current instance of the object. But wait! What this property returns is simply a reference to the application state object, not a clone. Provided for ASP compatibility.
CountGets the number of objects currently stored in the collection.
ItemIndexer property, provides read/write access to an element in the collection. The element can be specified either by name or index. Accessors of this property are implemented using Get and Set methods.
StaticObjectsGets a collection including all instances of all objects declared in global.asax using an <object> tag with the scope attribute set to Application.

Note that static objects and actual state values are stored in separate collections. The exact type of the static collection is HttpStaticObjectsCollection.

Methods of the HttpApplicationState Class

The set of methods that the HttpApplicationState class features are mostly specialized versions of the typical methods of a name/value collection. As Table 3 shows, the most significant extension entails the locking mechanism necessary to serialize access to the state values.

Table 3. HttpApplicationState Methods
AddAdds a new value to the collection. The value is boxed as an object.
ClearRemoves all objects from the collection.
GetReturns the value of an item in the collection. The item can be specified either by key or index.
GetEnumeratorReturns an enumerator object to iterate through the collection.
GetKeyGets the string key of the item stored at the specified position.
LockLocks writing access to the whole collection. No concurrent caller can write to the collection object until UnLock is called.
RemoveRemoves the item whose key matches the specified string.
RemoveAllCalls Clear.
RemoveAtRemoves the item at the specified position.
SetAssigns the specified value to the item with the specified key. The method is thread-safe, and the access to the item is blocked until the writing is completed.
UnLockUnlocks writing access to the collection.

Note that the GetEnumerator method is inherited from the base collection class and, as such, is oblivious to the locking mechanism of the class. If you enumerate the collection using this method, each returned value is obtained through a simple call to one of the get methods on the base NameObjectCollectionBase class. Unfortunately, that method is not aware of the locking mechanism needed on the derived HttpApplicationState class because of the concurrent access to the application state. As a result, your enumeration would not be thread-safe. A better way to enumerate the content of the collection is by using a while statement and the Get method to access an item. Alternatively, you could lock the collection before you enumerate.

State Synchronization

Note that all operations on HttpApplicationState require some sort of synchronization to ensure that multiple threads running within an application safely access values without incurring deadlocks and access violations. The writing methods, such as Set and Remove, as well as the set accessor of the Item property implicitly apply a writing lock before proceeding. The Lock method ensures that only the current thread can modify the application state. The Lock method is provided to apply the same writing lock around portions of code that need to be protected from other threads’ access.

You don’t need to wrap a single call to Set, Clear, or Remove with a lock/unlock pair of statements—those methods, in fact, are already thread-safe. Using Lock in these cases will only have the effect of producing additional overhead, increasing the internal level of recursion.

// This operation is thread-safe
Application["MyValue"] = 1;

Use Lock instead if you want to shield a group of instructions from concurrent writings:

// These operations execute atomically
int val = (int) Application["MyValue"];
if (val < 10)
    Application["MyValue"] = val + 1;

Reading methods such as Get, the get accessor of Item, and even Count have an internal synchronization mechanism that, when used along with Lock, will protect them against concurrent and cross-thread readings and writings:

// The reading is protected from concurrent read/writes
int val = (int) Application["MyValue"];

You should always use Lock and UnLock together. However, if you omit the call to UnLock, the likelihood of incurring a deadlock is not high because the .NET Framework automatically removes the lock when the request completes or times out, or when an unhandled error occurs. For this reason, if you handle the exception, consider using a finally block to clear the lock or expect to face some delay while ASP.NET clears the lock for you when the request ends.

Tradeoffs of Application State

Instead of writing global data to the HttpApplicationState object, you could use public members within the global.asax file. Compared to entries in the HttpApplicationState collection, a global member is preferable because it is strongly typed and does not require a hashtable access to locate the value. On the other hand, a global variable is not synchronized per se and must be manually protected. You have to use language constructs to protect access to these members—for example, the C# lock operator or, in Visual Basic .NET, the SyncLock operator. 

Memory Occupation

Whatever form you choose for storing the global state of an application, some general considerations apply about the opportunity of storing data globally. For one thing, global data storage results in permanent memory occupation. Unless explicitly removed by the code, any data stored in the application global state is removed only when the application shuts down. On one end, putting a few megabytes of data in the application’s memory speeds up access; on the other hand, doing this occupies valuable memory for the entire duration of the application.

For this reason, it is extremely important that you consider using the Cache object whenever you have the need for globally shared data. Unlike data stored with Application and global members, data stored in the ASP.NET Cache is subject to an automatic scavenging mechanism that ensures that the data is removed when a too high percentage of virtual memory is being consumed.The bottom line is that the Cache object was introduced specifically to mitigate the problem of memory occupation and to replace the Application object.

Concurrent Access to Data

Storing data globally is also problematic because of locking. Synchronization is necessary to ensure that concurrent thread access doesn’t cause inconsistencies in the data. But locking the application state can easily become a performance hit that leads to nonoptimal use of threads. The application global state is held in memory and never trespasses the machine’s boundaries. In multimachine and multiprocessor environments, the application global state is limited to the single worker process running on the individual machine or CPU. As such, it is not something really global. Finally, the duration of the data in memory is at risk because of possible failures in the process or, more simply, because of the ASP.NET process recycling. If you’re going to use the application state feature and plan to deploy the application in a Web farm or Web garden scenario, you’re probably better off dropping global state in favor of database tables. At the very least, you should wrap your global data in smart proxy objects that check for the existence of data and refill it if it’s not there, for whatever reason. Here’s a quick snapshot:

// Retrieve data
public object GetGlobalData(string entry)
    object o = Application[entry];
    if (o == null)
        // TODO:: Reload the data from its source

        // Return data
        return Application[entry];
    return o;
Video tutorials
- How To Install Windows 8

- How To Install Windows Server 2012

- How To Install Windows Server 2012 On VirtualBox

- How To Disable Windows 8 Metro UI

- How To Install Windows Store Apps From Windows 8 Classic Desktop

- How To Disable Windows Update in Windows 8

- How To Disable Windows 8 Metro UI

- How To Add Widgets To Windows 8 Lock Screen

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010
programming4us programming4us