Introduction
This article describes an AJAX Component for ASP.NET allowing the client to see a smooth progress bar showing a server side process. This control works in Internet Explorer 8+, Chrome, Firefox, and Opera.
Background
The only thing you will need to implement in your application is a web service or web method to return the progress values. Remember that you'll need only one web service for the entire web application but for test purposes, I used web methods on each test page of the test project.
Features
- Smooth Progress using value estimation
- HTML5 native progress for browsers supporting HTML5 and a substitute for older browsers
- Optional Message Box to display server messages and log
- Optional event handler to trigger postback upon completion
- Optional progress substitute to be displayed when process is running (It's useful when we can't calculate the actual progress and only know the beginning and end of the process.)
- Optional State object to hold objects in memory and use it on progress completion (like when generating a report takes time and we need to send the result to user when process is completed)
How It Works
Each instance of the ProgressBar
control has its own unique GUID named ProgressId
which is automatically generated upon construction of the class. There is a property named Progress
in ProgressBar
using this GUID allowing developers to control the progress and messages displayed on the optional message box.
Using the Code
First, you'll need to create a web service somewhere in the web project or a web method in the page you are using the control, but I recommend the web service, remember to include the [System.Web.Script.Services.ScriptService]
attribute.
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class ProgressStatus : System.Web.Services.WebService
{
[WebMethod]
public object getProgress(string progressId)
{
return Progress.GetResponse(progressId);
}
}
Then, include an instance of the ProgressBar
control in the desired usercontrol
or page
. You are going to need a ScriptManager
on the page too.
<hmc:ProgressBar
ID="ProgressBar1"
runat="server"/>
Also, you should set the properties of the control according to your needs.
On the code-behind, the main technique would be to allow the postback to occur and we start the process asynchronously. Please note the progress is a number between 0 and 1 and sending value 1 will trigger the Complete
event if set.
protected void btnStart_Click(object sender, EventArgs e)
{
Progress progress = ProgressBar1.Progress;
Thread thread = new Thread(() => Start(progress));
thread.Start();
btnStart.Enabled = false;
}
private void Start(Progress progress)
{
double max = 50;
for (int i = 0; i < max; i++)
{
Thread.Sleep(100);
progress.SetProgress(i / max);
progress.AddMessageLine("your message line here");
}
progress.SetProgress(1);
}
Properties
ServicePath
- This property indicates the path for the service sending the progress information. If not specified, the control assumes you are using a web method behind the page control is used on. Service_GetMethod
- Specifies the name of the method in the WebService
or on the page. Default value would be getProgress
and note the casing! MessageTargetId
- Indicates the optional target control to display received messages. ProgressId
is a unique GUID indicating the process, you can change the value so that all instances of the control in a certain page have the same ProgressId
and all users can see the same progress results. (This is typicially done when only one instance of the process is allowed in the entire application.) ProgressControlId
- Specifies optional target control to be shown when progress started. This can be used for processes for which we can't calculate the progress untill they are finished. Using this property will hide the progress bar. Interval
- The interval between each request to web service in milliseconds. Please refrain from using small values. The optimal value is 1000-5000 ms. SingleLine
- Indicates whether to show only the last line of the messages or all received lines. OnClientComplete
- Gets or sets the client-side script that executes when a ProgressBar
control's Complete
event is raised.
Events
Complete
- This event will be triggered when control receives 100% (1.0) from the server. It can be used to show the client additional data like result of a query, etc. (Using this event will cause a Postback upon completion)
The following sample shows how to maintain some data during the progress and retrieve it upon completion.
protected void btnStart_Click(object sender, EventArgs e)
{
Progress progress = ProgressBar1.Progress;
progress.State = new MyDataType();
Thread thread = new Thread(() => Start(progress));
thread.Start();
btnStart.Enabled = false;
}
private void Start(Progress progress)
{
var mydata = (MydataType)progress.State;
}
protected void ProgressBar1_Complete(object sender, EventArgs e)
{
var progressBar = (ProgressBar)sender;
var mydata = (MyDataType)progressBar.Progress.State;
btnStart.Enabled = true;
Label1.Text = DateTime.Now.ToString();
}
Points of Interest
When dealing with time consuming operations on the server side (i.e., importing/processing large Excel files, generating large reports, performing database operations etc.), the user might think the server is not responding or even face HTML timeout exception. This control helps developers and designers to have a solution for mentioned problems and improve user experience.
Known Issues
- Although we are not using AjaxControlToolkit, you are going to need your web application to reference the AjaxControlToolkit library. This won't be a big problem as most web applications are already using it.
Final Word
Please don't hesitate to inform me of any issues you might face or suggestions regarding the control. Also please feel free to use this component in your projects and please drop me a line if you are using it in a commercial application.
Don't forget to rate the article.