Executing Long Running Operations - Part II
Introduction
In the Part-I of this two part
series we saw how to handle long running operations in Web Services. You may
need to execute such operations in web applications also. This article shows you
how to use multithreading capabilities of .NET framework to achieve this.
The scenario
The example that we are going to develop consists of following steps:
- We have a web form (WebForm1.aspx) that is our main web page containing
long running operation.
- You initiate the long running operation by clicking on the appropriate
button provided on the web form.
- This triggers the operation in a new thread.
- A new window is opened to indicate the status of processing.
- Your first web form (WebForm1.aspx) can be used to do some other things.
- Once the operation is over the status window indicates that it is
complete.
- You can now close the status windows and continue using the main form.
The Solution
- Create a new web application (C#) on VS.NET
- Add two web forms to it called MainForm.aspx and StatusForm.aspx
- Drag and drop a button (Button1) on the main form
- Go in the code behind file of Global.asax
- Declare a public static variable here called ProcessingResults. This
variable will be used to check if the processing is over.
public static ArrayList ProcessingResults=new ArrayList();
- Go in the code behind of main form.
- Declare a variable called g of type Guid. This variable uniquely
identifies our long running operation and is stored in the above ArrayList.
Guid g;
- Create a function called StartProcessing() that represents our long
running task.
- Note that this function must be void and not accepting any parameters
because we would like to run it on a new thread.
public void StartProcessing()
{
DateTime dt1=DateTime.Now;
DateTime dt2=dt1.AddMinutes(2);
TimeSpan ts=new TimeSpan(0,0,0);
while(true)
{
dt1=DateTime.Now;
if(dt2.Subtract(dt1)==ts)
{
break;
}
}
Global.ProcessingResults.Add(g.ToString());
}
- Note how we have added the Guid value in the ProcessingResults ArrayList
at the end of the operation.
- Now, write the Click event handler of Button1 as follows:
private void Button1_Click(object sender, System.EventArgs e)
{
g=Guid.NewGuid();
ThreadStart ts=new ThreadStart(this.StartProcessing);
Thread t=new Thread(ts);
t.Start();
Response.Write("<script>window.open
('statusform.aspx?id=" + g.ToString() + "')</script>");
}
- Here, we trigger the processing by creating a new thread. The
ThreadStart delegate wraps the function StartProcessing()
- We then emit certain client side JavaScript to open a new window and
display StatusForm.aspx in it.
- We also pass the same Guid to this form in the query string.
- Go in the code behind of StatusForm.aspx and write following code in its
Page_Load event:
private void Page_Load(object sender, System.EventArgs e)
{
string g=Request.QueryString["id"];
if(Global.ProcessingResults.BinarySearch(g)>=0)
{
Response.ClearHeaders();
Label1.Text="Processing Completed!";
Global.ProcessingResults.Remove(g);
}
else
{
Response.AddHeader("Refresh", "2");
}
}
- Here, we add a response header to this page so that after every 2
seconds it gets refreshed automatically.
- With each refresh we check the ProcessingResults ArrayList for
occurrence of id parameter passed via query string. If that is found it
indicates that the thread has finished the processing (recollect that we
have added it to the same ArrayList at the end of StartProcessing()
function).
- We then remove the Guid from the ArrayList.
Summary
Using .NET multithreading capabilities you can handle long running operations
in web applications nicely. In this example we initiated the operation by
creating a new thread and then polling the server for the results of processing.
If you do not need the status of process completion then you can skip the logic
of storing the Guid and polling the server.