Table of Contents
There are a lot of articles available on different ways of managing the states in the web. I was not able to find details on Application Object and events. So I read different books and articles and thought of sharing my knowledge with all of you. Hope you will like it and give your feedback and suggestions.
As we all know, web is stateless
. A Web page is recreated every time it is posted back to the server. In traditional web programming, all the information within the page and control gets wiped off on every postback. To overcome this problem, ASP.NET Framework provides various ways to preserve the states at various stages like controlstate, viewstate, cookies, session, etc. These can be defined in client side and server side state management. Please see the image below:
Figure: Options available to maintain the state
There are lot more written about most of them. In this article, I am going to explore mainly Application state, Application events and Application Objects.
First, I am going to explain ASP.NET Application Lifecycle. One needs to really understand the application Lifecycle, so that one can code efficiently and use the resources available. Also it is very important to discuss, as we are going to Application level events, objects, etc.
ASP.NET uses lazy initialization technique for creating the application domains, i.e., Application domain for an application is created only when the first request is received by the web server. We can categorise Application life cycle in several stages. These can be:
- Stage 1: User first requests any resource from the webserver.
- Stage 2: Application receives very first request from the application.
- Stage 3: Application basic Objects are created.
- Stage 4: An
HTTPapplication
object is assigned to the request.
- Stage 5: And the request is processed by the
HTTPApplication
pipeline.
I'll explain the points one by one.
Stage 1: The Application life cycle starts when a user hits the URL by typing it in the browser. The browser sends this request to the webserver. When webserver receives the request from the browser, it examines the file extension of the requested file and checks which ISAPI extension
is required to handle this request and then passes the request to the appropriate ISAPI extension.
Figure: URL Processing
Note 1: If any extension is not mapped to any ISAPI extension, then ASP.NET will not receive the request and the request is handled by the server itself and ASP.NET authentication, etc. will not be applied.
Note 2: We can also make our own custom handler, to process any specific file extension.
Stage 2: When ASP.NET receives the first request, the Application manager creates an application domain for it. Application domains are very important because they provide the isolation amongst various applications on the webserver and every application domain is loaded and unloaded separately, and in application domain an instance of class HostingEnvironment
is created which provides access to information about all application resources.
Figure: ASP.NET Handling first request
Stage 3: After creating the application domain and hosting environment, ASP.NET initializes the basic objects as HTTPContext
, HTTPRequest
and HTTPResponse
. HTTPContext
holds objects to the specific application request as HTTPRequest
and HTTPResponse
.HTTPRequest
contains all the information regarding the current request like cookies, browser information, etc. and HTTPResponse
contains the response that is sent to client.
Stage 4: Here all the basic objects are being initialized and the application is being started with the creation of HTTPApplication
class, if there is Global.asax (It is derived from HTTPApplication
class) in the application, then that is instantiated.
Figure: Multiple requests processed by ASP.NET
Note: When the application is accessed for the first time, the HTTPApplication
instance is created for further requests. It may be used for other requests as well.
Stage 5: There are a lot of events executed by the HTTPApplication
class. Here, I have listed down a few important ones. These events can be used for any specific requirement.
Fig: Application Events
To handle application events or methods, we can have a file named Global.asax in the root directory of your application. At any single point of time, an HTTPApplication
instance handles only one request, so we don't need to think about locking and unlocking of any non static
members, but for static
members we do require. I'll discuss it in detail in a later section of this article. Following are the commonly used events in the global.asax file.
Figure: Methods in Global.asax
If we are going to change the source code, then ASP.NET requires to recompile into assemblies and also the application will restart as well. In spite of this, there are also certain things that force the application to get restarted. If we'll change in the following folder whether adding, modifying or deleting, the application will restart:
Application state is one of the ways available to store some data on the server and faster than accessing the database.The data stored on the Application state is available to all the users(Sessions) accessing the application. So application state is very useful to store small data that is used across the application and same for all the users. Also we can say they are global variables available across the users. As I am saying small data, we should not store heavy data in ApplicationState
because it is stored on the server and can cause performance overhead if it is heavy. We'll discuss it later. Technically the data is shared amongst users via HTTPApplcationState
class and the data can be stored here in key value pair
. It can also be accessed through Application
property of the HTTPContext
class.
As I have already discussed above, an instance of HttpApplicationState
is created when first time a request comes from any user to access any resource from the application. And this can be accessed through the property Application
property of HTTPContext
Object. All HTTPModules
and Handlers
have access to this property. The lifetime of the values spans through the lifetime of the ASP.NET application until the application is unloaded. Normally, we set these Application
variables in Application_OnStart
event in Global.asax file and access and modify through ASP.NET pages.
One thing to keep in mind is that application state stores the data as of Object
type, so at the time of reading, the values we need to convert it in the appropriate type.
So normally, we use to store the Application wise data in Application state which is shared across the users. So we can save the data in Application_OnStart
method in Global.asax file as:
void Application_Start(object sender, EventArgs e)
{
Application["Message"] = "Welcome to my Website";
}
We can also save object of some Class in Application
variable. Let's say we have a class as:
public class Employee
{
private string _name;
public string Name {
get
{
return _name;
}
set
{
_name = value;
}
}
private decimal _annualSalary;
public decimal AnnualSalary
{
get
{
return _annualSalary;
}
set
{
_annualSalary = value;
}
}
public Employee()
{
}
}
Put this class file in App_Code folder. Now class will be available throughout the application so also in Global.asax. Now to save it in Application_OnStart
as:
void Application_Start(object sender, EventArgs e)
{
Employee objEmployee = new Employee();
objEmployee.Name = "Brij";
objEmployee.AnnualSalary = 1000000;
Application["EmployeeObject"] = objEmployee;
}
Note: Here one thing I would like to mention is that we don't require to serialize the object to store in Application state as we need to keep in mind in case of viewstate, etc. So there is no need of serialization
here. :) We can also modify these values from any method in the application. Here I am modifying Application["Message"]
in onclick
method of a button in a page as:
protected void Button1_Click(object sender, EventArgs e)
{
Application["Message"] = "Welcome Dude!!";
}
Now we'll get the modified values whenever we try to access it. Let's also add a new variable on another button Click event as:
protected void Button3_Click(object sender, EventArgs e)
{
Application["NewValue"] = "Hello";
}
This value will also be available throughout the application life. One thing I also want to discuss is that Application state is not thread safe
so it can be accessed by multiple threads at the same time, i.e., if we have stored some value in Application state say some counter and we increase it whenever a particular page is accessed. So at a single point of time, two instances of page of a different session can read the same value and update it. So we'll not get the desired result. So here we need some synchronisation mechanism so that at a single point of time only, one can update its value. Here we can call the System.Web.HttpApplicationState.Lock
method, set the application state value, and then call the System.Web.HttpApplicationState.UnLock
method to unlock the application state, freeing it for other write or update it as:
if (Application["Counter"] != null)
{
Application.Lock();
Application["Counter"] = ((int)Application["Counter"]) + 1;
Application.UnLock();
}
So by this way, we can avoid writing the same value from multiple Threads at the same time.
So to read from Application state is fairly simple. We should just have a safety check to see whether the value we are accessing is null
, if the data will not be in Application state is not there then it will return null
and if we'll try to cast it in any different type, it'll throw an exception. As I already discussed, Application state stores the data in object form so we need to typecast after reading it. So we can read the value as:
if(Application["Message"] !=null)
{
string message = Application["Message"] as string;
}
The object also can be read as:
if (Application["EmployeeObject"] != null)
{
Employee myObj = Application["EmployeeObject"] as Employee;
string Name = myObj.Name;
}
A classic example of Application variable can be to show the number of online user in a website. This can be done in the following steps:
- Add an online counter variable
ApplicationStart
method of Global.asax file as:
Application["OnlineCounter"] = 0;
So in this, a variable will be added when the application first starts and will be initialized to 0
as there will be no logged in user at that point of time.
- Now as we know whenever a new user opens the website, a new session is created and
Session_Start
method of Global.asax is called. So we can increase the counter in this method as:
void Session_Start(object sender, EventArgs e)
{
if (Application["OnlineCounter"] != null)
{
Application.Lock();
Application["OnlineCounter"] =
((int)Application["OnlineCounter"]) + 1;
Application.UnLock();
}
}
We should use the Locks, else we may get the wrong result because this may be updated at the same time and updated data is not correct. How: Let's say we currently have Application["OnlineCounter"]
is 5
and at the same time, two sessions read the value 5
and make an increment to 6
and updated it. Application state as 6. So although two users are logged in, the counter is increased by one only. So to avoid this, we should use the locks.
- So also at the time session ends, we should decrease it by one. As I already discussed, an event
Session_End
is fired whenever a session ends. So it can be done as:
void Session_End(object sender, EventArgs e)
{
if (Application["OnlineCounter"] != null)
{
Application.Lock();
Application["OnlineCounter"] =
((int)Application["OnlineCounter"]) - 1;
Application.UnLock();
}
}
- And this value can be accessed throughout the application at any point of time in the application as:
if (Application["OnlineCounter"] != null)
{
int OnlineUsers = ((int)Application["OnlineCounter"]);
}
and this value can be used anywhere in the application.
- Application state is stored in memory of webserver, so huge amount of data can cause severe performance overhead. Also keep in mind that these variables will be stored in memory till the application ends whether we need the entire time or not. So use it judiciously.
- If the application goes down or is restarted, then all the data stored in Application state is lost.
- Also Application data is not shared between multiple servers in webfarm scenario.
- Application also doesn't work in case of Webgarden. Variables stored in application state in either of those scenarios are global only to the particular process in which the application is running. Each application process can have different values.
- Application state is not thread safe, so we must keep the synchronisation in mind as discussed above.
Although both provide the same feature and can be used to store the data at application level, there are a lot of differences between both.
Sr No |
Application State |
Cache |
1 |
Application variables are one of the techniques provided by ASP/ASP.NET to store the data at application level and this is available to all users. |
Cache is one technique provided by ASP.NET to store the data at the application level with many options. |
2 |
Application variables are available throughout the lifecycle of the application until explicitly removed or overridden. |
Cache is volatile. It provides the opportunity to automatically expire the data based on the settings or memory gets reclaimed when memory is scarce. |
3 |
Application variable should be used only when data is limited, i.e., it should not be like we store some dataset and keep adding the data in same, which may lead to choke the webserver |
Cache provides a flexible way to store data on the webserver and also get removed when memory becomes low. |
Feedback is always the key area for me. I would request you all to share your feedback and give me some suggestions, which would encourage and help in more writing.