In most ASP.NET Web Applications interaction with the user is fairly simple and can be accomplished within the normal page life cycle. The client web browser dictates the amount of time allowed which is normally 30 seconds, so any processing must be accomplished within that period. Lets say your process takes 15 seconds, you could simply perform the process during the
Page_Load or another
Event. However, causing the user to wait 15 seconds could lead to user frustration and clicking multiple times. Ideally you want to minimize the amount of time used for the page life cycle to keep your web application responsive. So when you have a long running process you have conflicting needs, both to stay responsive to the user and to provide sufficient time to complete your task. To satisfy both needs we need a happy medium to stay responsivle and complete the task.
When you make the leap to perform a long running tasks in the background we need to design the page in a manor to allow the user to launch the process, monitor the process and see the results. To get started we will create a page which will be used to perform these three tasks.
To simplify the process we will create a single
ASP.NET AJAX page to perform these three functions. Three different functions will be grouped into 3 separate views withing a multiview control. The multiview control is contained with an update panel which will be used to provide seemless feedback to the user as shown in the figure below.
Figure 1 – Page Layout
The first of the three views above simply provides the mean to start the process. The second view contains an ASP.NET AJAX loading image, status text and an AJAX timer. And finally the third shows completion. The markup for these views is listed below.
<asp:ScriptManager ID=”ScriptManager2″ runat=”server”>
<asp:UpdatePanel ID=”UpdatePanel2″ runat=”server”>
<asp:MultiView ID=”mvvProcess” runat=”server” ActiveViewIndex=”0″>
<asp:View ID=”vLaunch” runat=”server”>
<asp:Button ID=”Button1″ runat=”server” onclick=”Button1_Click” Text=”Start” />
<asp:View ID=”vProgress” runat=”server”>
<asp:Image ID=”Image1″ runat=”server” ImageUrl=”ajax-loader.gif” />
<asp:Label ID=”Label1″ runat=”server” Text=”Starting”></asp:Label>
<asp:Timer ID=”timUpdate” runat=”server” Enabled=”False” Interval=”1000″ ontick=”timUpdate_Tick”> </asp:Timer>
<asp:View ID=”vComplete” runat=”server”>
<asp:Label ID=”Label2″ runat=”server” Text=”Complete”></asp:Label>
Next we jump into the code behind the first view and the Start button. The click event handler for the Start button is listed below:
protected void Button1_Click(object sender, EventArgs e)
//Start the Process
Session[“complete”] = false;
Session[“status”] = “”;
Thread t = new Thread(new ParameterizedThreadStart(ThreadProcess));
//Switch the View
timUpdate.Enabled = true;
The Start button click event handler first sets a complete and status session values to the desired inital values. You’ll notice we are locking the Session object. The purpose behind this is to prevent conflicts and/or the possibility for corrupting Session when the thread is running. Next we create a new Thread and give it the handle to a
ThreadProcess method. Then we start the thread and pass in the Session object to the thread. You may be thinking why the Thread needs Session since the method is in the code behind. The answer is simple, Session is tied to the life-cycle of the page, so while the page is active Session is available. But when the page is not being processed the Session object is invalid. So in order for the Thread to access Session and save provide status updates back to the user we need to give it a handle. Finally the button click sets the active view and enables the AJAX update timer. The next code block is for the
ThreadProcess method used to perform the background process.
private void ThreadProcess(object data)
System.Web.SessionState.HttpSessionState s = (System.Web.SessionState.HttpSessionState)data;
for (i = 0; i < 30; i++)
//Update the status for the user
s[“status”] = “Running: ” + i.ToString();
//Add some delay to simulate work
s[“complete”] = true;
ThreadProcess method first grabs the reference to Session passed into the method. Then it performs a simple loop for 30 times, updates session status each time, putting the thread to sleep for 1 second each time. After finishing the loop the session complete status is updated and the thread terminates. Note, again we are locking session each time it is accessed to prevent collisions with the main page.
The next code block is for the AJAX Update timer Tick event.
protected void timUpdate_Tick(object sender, EventArgs e)
Label1.Text = Session[“status”].ToString();
if (Session[“complete”] as bool? == true)
timUpdate.Enabled = false;
This event handler first updates the status and checks to see if the session complete flag has been set. If the session complete flag is set, it will then disable the update timer and set the multiview to the Complete view. After pressing the Start button, the user should see the status change from Running 1 thru Running 30 and finally to Complete as shown by the following 3 images.
Figure 2 – Start View
Figure 3 – Running View
Figure 4 – Complete View
While this is effective and does provide a simple method for performing long running background process it does have its disadvantages. Using Session for communication does add overhead, not to mention the other drawbacks related to Session including scalability and memory usage. Since this example used Session we also need to lock the Session object to prevent collisions and/or corruption this again adds overhead. As an alternative to using Session you could also use a Database table for status information. While this eliminates the Session and locking overhead it does mean additional hits to a table; however, it eliminates the scalability issues associated with Session.
In addition to the alternative for Session we can also look at different ways of background threading. The most obvious is to take advantage of the
ThreadPool. Simply put, we could add an item to the
ThreadPool and allow it to perform the work. While at first this may sound like a good idea; in ASP.NET the
ThreadPool serves a very important role. In fact the
ThreadPool is used for processing all requests from the user. So if you were to start tying up the
It is also important to note that during the second step in the process above, the AJAX timer is being triggered once per second which causes the UpdatePanel to refresh and the code behind to be executed. In a production situation it more realistic to increase the Timer interval value to 3 to 5 seconds to reduce the number of hits to the server.
There are alternative methods for executing background tasks within ASP.NET, the simple technique used above is just that simple. There is very little to setup and easy to learn, making it quick to implement and support in your next project.