For the English version, see: http://dflying.dflying.net/1/archive/100_building_a_real_time_progressbar_using_aspnet_atlas.html
When some long-term operations are being performed in the background, it would be a very rare achievement if a progress bar could be provided on the page to show the real progress, instead of letting users wait unknowingly or make simple estimates in the past. place. It's now entirely possible to do this using ASP.NET Atlas. This article will discuss how to accomplish this functionality and introduce some basic concepts about Atlas client control development. You can also download sample programs and source files here.
The idea of implementing a progress bar on a web page is actually very simple: write a client-side Atlas control, request the server every once in a while, and use the returned current progress data to update the display of the progress bar. In this example, there will be four parts of code:
a Web Service that takes a long time to complete
A Web Service used to query the progress of the above Web Service
The client Atlas progress bar (ProgressBar) control is responsible for maintaining client logic and outputting the visual UI. This is also the most important component in this example and can be reused in the development of other pages or programs in the future. An ASP.NET test page containing the above Web Service and controls. Below we implement the above four steps step by step:
it takes a long time Web Service that takes a long time to complete
In an actual program, a Web Service that takes a long time to complete may have the following statement:
1[WebMethod]
2public void TimeConsumingTask()
3{
4 ConnectToDataBase();
5 GetSomeValueFromDataBase();
6 CopySomeFilesFromDisk();
7 GetARemoteFile();
8}
In this way, we can insert some auxiliary methods to determine the current progress completion status. setProgress(int) is used to set the current progress completion percentage:
1[WebMethod]
2public void TimeConsumingTask()
3{
4 setProgress(0);
5ConnectToDataBase();
6 setProgress(10);
7 GetSomeValueFromDataBase();
8 setProgress(40);
9 CopySomeFilesFromDisk();
10 setProgress(50);
11 GetARemoteFile();
12 setProgress(100);
13}
In this example, we only use Cache to store progress completion information and use the Thread.Sleep() method to simulate the delay of the operation:
1[WebMethod]
2public int StartTimeConsumingTask()
3{
4 string processKey = this.Context.Request.UserHostAddress;
5 string threadLockKey = "thread" + this.Context.Request.UserHostAddress;
6 object threadLock = this.Context.Cache[threadLockKey];
7 if (threadLock == null)
8 {
9 threadLock = new object();
10 this.Context.Cache[threadLockKey] = threadLock;
11 }
12
13 // Only allow 1 running task per user.
14 if (!Monitor.TryEnter(threadLock, 0))
15 return -1;
16
17 DateTime startTime = DateTime.Now;
18
19 // Simulate a time-consuming task.
20 for (int i = 1; i <= 100; i++)
twenty one {
22 // Update the progress for this task.
23 this.Context.Cache[processKey] = i;
24 Thread.Sleep(70);
25}
26
27 Monitor.Exit(threadLock);
28
29 return (DateTime.Now - startTime).Seconds;
30}
31
Web Service for querying progress
is easy to implement, just get the progress information from Cache:
1[WebMethod]
2public int GetProgress()
3{
4 string processKey = this.Context.Request.UserHostAddress;
5 object progress = this.Context.Cache[processKey];
6 if (progress != null)
7 {
8 return (int)progress;
9}
10
11 return 0;
12}
Client-side progress bar (ProgressBar) control
Step 1: Inherit from Sys.UI.Control
The ProgressBar control should inherit from the Atlas control base class Sys.UI.Control and declare it as a sealed class (sealed class, which can no longer be inherited) ). The Sys.UI.Control base class contains some operations and methods common to all controls. For example, associating yourself with an HTML element (also known as binding), etc. At the same time, it must be registered to let Atlas know about this new type for future declaration and use, for example, so that Atlas can obtain the description of this type, etc.
1Sys.UI.ProgressBar = function(associatedElement) {
2 Sys.UI.ProgressBar.initializeBase(this, [associatedElement]);
3
4}
5Type.registerSealedClass('Sys.UI.ProgressBar', Sys.UI.Control);
6Sys.TypeDescriptor.addType('script','progressBar', Sys.UI.ProgressBar);
7
Step 2: Add private members and write corresponding Setter/Getter
Next, you need to add some properties to set our control. In this example, we need three properties:
Interval. The interval between each time the progress is re-queried and the progress bar is updated. Unit: millisecond
Service Url. The path of the Web Service file.
Service Method. The name of the method to obtain progress information.
These properties should strictly follow Atlas' naming convention: Getters should start with 'get_', and Setter should start with 'set_' and pass in a parameter. You also need to add descriptions of these properties in the control's descriptor. The description method (descriptor) will be explained in the fourth step. For example, for the Service Method attribute, we have the following statement:
1var _serviceMethod;
2
3this.get_serviceMethod = function() {
4 return _serviceMethod;
5}
6
7this.set_serviceMethod = function(value) {
8 _serviceMethod = value;
9}
Step 3: Use the Timer control to query the Web Service
Sys every once in a while. Timer is used to call a method (emit an event) every time. We can define a delegate to point to this method and do it every time. Query this Web Service within a time period. In order to avoid browser memory leaks, you should remember to do some necessary cleanup when the control is destructed (dispose).
Also, note that you should not send a second request when the previous request did not return.
1var _timer = new Sys.Timer();
2var _responsePending;
3var _tickHandler;
4var _obj = this;
5
6this.initialize = function() {
7 Sys.UI.ProgressBar.callBaseMethod(this, 'initialize');
8 _tickHandler = Function.createDelegate(this, this._onTimerTick);
9 _timer.tick.add(_tickHandler);
10 this.set_progress(0);
11}
12
13this.dispose = function() {
14 if (_timer) {
15 _timer.tick.remove(_tickHandler);
16 _tickHandler = null;
17 _timer.dispose();
18}
19 _timer = null;
20 associatedElement = null;
21 _obj = null;
twenty two
23 Sys.UI.ProgressBar.callBaseMethod(this, 'dispose');
twenty four}
25
26this._onTimerTick = function(sender, eventArgs) {
27 if (!_responsePending) {
28 _responsePending = true;
29
30 // Asynchronously call the service method.
31 Sys.Net.ServiceMethod.invoke(_serviceURL, _serviceMethod, null, null, _onMethodComplete);
32}
33}
34
35function _onMethodComplete(result) {
36 // Update the progress bar.
37 _obj.set_progress(result);
38 _responsePending = false;
39}
Step 4: Add control method
We should be able to control the start/stop of the progress bar. Moreover, for an Atlas control, the related description method (descriptor) is also necessary. Atlas will use it to describe this type of information.
1this.getDescriptor = function() {
2 var td = Sys.UI.ProgressBar.callBaseMethod(this, 'getDescriptor');
3 td.addProperty('interval', Number);
4 td.addProperty('progress', Number);
5 td.addProperty('serviceURL', String);
6 td.addProperty('serviceMethod', String);
7 td.addMethod('start');
8 td.addMethod('stop');
9 return td;
10}
11
12this.start = function() {
13 _timer.set_enabled(true);
14}
15
16this.stop = function() {
17 _timer.set_enabled(false);
18}
OK, the client control is completed so far. We save it as ProgressBar.js.
ASP.NET Testing Page ASP.NET Testing Page
For any Atlas page, the first thing we need to do is add a ScriptManager server control. In this example we will refer to the ProgressBar control, the Web Service that takes a long time to complete, and the Progress Query Web Service. (These two Web Services are located in the same file: TaskService.asmx)
1<atlas:ScriptManager ID="ScriptManager1" runat="server" >
2 <Scripts>
3 <atlas:ScriptReference Path="ScriptLibrary/ProgressBar.js" ScriptName="Custom" />
4 </scripts>
5 <Services>
6 <atlas:ServiceReference Path="TaskService.asmx" />
7 </Services>
8</atlas:ScriptManager>
Next is the layout and style of the page:
1<style type="text/css">
2* {}{
3 font-family: tahoma;
4}
5.progressBarContainer {}{
6 border: 1px solid #000;
7 width: 500px;
8 height: 15px;
9}
10. progressBar {}{
11 background-color: green;
12 height: 15px;
13 width: 0px;
14 font-weight: bold;
15}
16</style>
17
18<div>Task Progress</div>
19<div class="progressBarContainer">
20 <div id="pb" class="progressBar"></div>
21</div>
22<input type="button" id="start" onclick="startTask();return false;" value="Start the Time Consuming Task!" />
23<div id="output" ></div>
Finally, there is a piece of JavaScript to start the Web Service that takes a long time to complete and let the ProgressBar control start working:
Screenshots and Downloads
Now everything is done and ready to run!
Page initialization:
Running:
Run completed:
Sample programs and source files can be downloaded here .