Home > Articles > Programming > ASP .NET

This chapter is from the book

This chapter is from the book

Displaying a Progress Bar Graphic

A static "please wait" message is fine, but it could not be described as eye-catching, and it gives no indication that anything is actually happening. The server could die while the message is being shown, leaving you still staring at the "please wait" message three days later. It's nice to have some kind of indication that the Web site is still alive and really is working furiously to generate the results you asked for.

Unfortunately, with the way that Web browsers and HTTP work, this isn't easy to achieve. Each request/response is treated as a single unit of operation, and there is no persistent connection over which status information can be passed. There are ways around this, of course, but they tend to hit performance and cause undue server loading. You'll see an example of this in the section Implementing a Staged Page Load Process, later in this chapter.

An alternative is to display something that makes it look like the browser is working hard but actually bears no relationship to what's happening on the server. When you do this, you avoid the need for extra connections while the main process is taking place, and yet you still satisfy the user's desire to see something happening. The simplest solution is to use an animated GIF file in the page instead of or in addition to the "please wait" message.

Figure 3.6 shows the "please wait" page for this example. Instead of just a text message, you now also have a progress bar that appears to reflect the state of the long-running process that is generating the results the user is waiting for.

As intimated earlier, however, the progress bar is an illusion in that it will keep moving, regardless of whether the page takes a minute or a month to appear. But by carefully choosing the timing of the animation in the GIF file to match the anticipated average response times for average users, you can get it to look quite realistic.

Figure 3.6Figure 3.6 Displaying a progress bar while loading another page.

Other than the appearance of the progress bar, the remainder of this example looks the same as the previous example, which displays just the "please wait" text message. Therefore, the following sections concentrate on what's different in the declaration of the HTML, the server controls, and the code used to drive this page compared to the previous example.

Achieving True and Accurate Status Displays

To achieve a real page-loading status display, you can arrange for your server-side code to flush chunks of output to the client as it carries out the processing required to generate the results. These chunks of output could be client-side script that writes status details within the current browser page or even just simple <img> elements that load images to indicate progress of the operation. As an example, the MSN Expedia Web site (http://www.expedia.com) flushes partial page output to the browser, as you can see if you view the source of the page while it's searching for that holiday in Florida you keep promising your kids. However, it also uses a "dummy" animated graphic, just as this example does, which effectively indicates nothing about the actual underlying process of the operation.

The Progress Bar Animated Graphic Files

We provide four different versions of the animated progress bar graphic in the images folder of the examples you can download for this book (from http://www.daveandal.net/books/6744/). The only difference between them is the speed at which the progress display moves from left to right. The details of these graphics files are summarized in Table 3.1.

Table 3.1 The Progress Bar Animated GIF Files for This Example

Filename

Description

progressbar10.gif

The indicator progresses at a steady speed from left to right in approximately 10 seconds, and it remains at the fully right (complete) position for 10 seconds before starting again.

progressbar20.gif

The indicator progresses at a steady speed from left to right in approximately 20 seconds, and it remains at the fully right (complete) position for 10 seconds before starting again.

progressbar30.gif

The indicator progresses at a steady speed from left to right in approximately 30 seconds, and it remains at the fully right (complete) position for 10 seconds before starting again.

progressbarlog.gif

The indicator progresses in logarithmic fashion from left to right in approximately 30 seconds, starting quickly and then getting slower. It remains at the fully right (complete) position for 10 seconds before starting again.


Displaying the Progress Bar Graphic

In theory, building the progress bar sample page should be easy. You just have to insert an <img> element into the section of the page that is displayed for Stage 2 of the process in the previous example, and you're done, right? However, most Web developers approach these trivial tasks with trepidation and with a knowledge gleaned from experience that nothing ever works quite as you expect when dealing with Web browsers—especially Web browsers from different manufacturers.

It turns out that trepidation is definitely justified here. Simply adding an <img> element fails to work properly because as soon as the redirection is initiated by the <meta> element, most browsers stop loading any images for the current page. In this case, unless the progress bar is already cached (and the server is extremely responsive when the browser checks whether the file has changed since it was cached), the result is a "missing image" placeholder instead of a progress bar.

The solution to this problem is to force the browser to delay for a few seconds—long enough to load the progress bar graphic—before beginning the refresh process that requests the next page. You can set this delay to 3 seconds in the sample page by changing the content attribute you add to the <meta> element in the Page_Load event handler:

mtaRefresh.Attributes.Add("content", "3;url=" & sRefreshURL)

Now the page works fine in recent Netscape, Mozilla, and Opera browsers. But it still doesn't work properly in Internet Explorer. It seems that Internet Explorer "turns off" the animation in animated GIF files as soon as a new page is requested. After the 3-second delay, the progress bar just stalls—which ruins the whole effect! So, for Internet Explorer, you have to find an alternative approach, as described in the following sections.

An Alternative Page-Loading Technique for Internet Explorer

We experimented with several seemingly obvious approaches to loading the progress bar graphic and reloading the page using client-side script in Internet Explorer, all to no avail. It seems that the only way to circumvent the issue with the stalled animated graphic is to find a completely different way to load the next page (that is, reload the current page with the customer ID in the query string).

Internet Explorer 5 and higher have access to the MSXML parser component; it is part of a Windows installation and is distributed with Internet Explorer as well. Part of the MSXML parser component is an object named XMLHTTP, which you can use to request a resource from the server in the background while a page is loaded and displayed in the browser.

The XMLHTTP object is instantiated and manipulated with client-side script within a Web page, and it exposes properties and methods that allow you to make GET and POST requests to a server both synchronously and asynchronously. Although it is ostensibly designed for fetching XML documents, it works equally well fetching any type of resource, including HTML pages that probably aren't fully XML (or XHTML) compliant.

Loading Pages with the XMLHTTP Object

The process for using the XMLHTTP object is relatively simple, especially if you are happy to load the new page synchronously. You can create an instance of the XMLHTTP object by using the following:

var oHTTP = new ActiveXObject("Microsoft.XMLHTTP");

Next you open an HTTP connection, specifying the HTTP method (usually "GET" or "POST"), the URL of the target resource, and the value false to indicate that you want synchronous operation. Then you can use the send method to send the request:

oHTTP.open("method", target-url, false);
oHTTP.send();

After the response has been received from the server, you test the status property (the value of the HTTP status header) to see if it is 200 (which means "OK") and extract the page as a string from the XMLHTTP object by using the following:

if (oHTTP.status == 200)
 sResult = oHTTP.responseText;
else
 // an error occurred

However, if you use synchronous loading, the browser will not respond to any other events (including animating the GIF file) while the request for the next page is executing. Instead, you need to use asynchronous loading to allow the browser to carry on reacting as normal while the server creates and returns the new page.

Asynchronous Loading with the XMLHTTP Object

For asynchronous loading, you first have to specify the name of a callback function that will be executed each time the readystate property of the XMLHTTP object changes and specify true for the third parameter of the open method:

oHTTP.onreadystatechange = myCallbackHandler;
oHTTP.open("method", target-url, true);
oHTTP.send();

The callback function you specify will be executed several times as the XMLHTTP object fetches the response from the server. When the response is complete, the value of the readystate property will be 4, and at that point you can test for an error and extract the page as a string:

function myCallbackHandler () {
 if (oHTTP.readyState == 4) {
  if (oHTTP.status == 200)
   sResult = oHTTP.responseText;
  else
   // an error occurred
 }
}
Using the XMLHTTP Object in the Progress Bar Sample Page

Listing 3.5 shows the client-side code included in the progress bar sample page. It works exactly as just demonstrated, with the only additions being a test to see that an instance of the XMLHTTP object was successfully created and the display of any error messages in a <span> element, located below the progress bar graphic in the page.

Listing 3.5 Loading the Results Page with XMLHTTP

<script language='javascript'>
<!--
// variable to hold reference to XMLHTTP object
var oHTTP;

function loadTarget(sURL) {
 // create instance of a new XMLHTTP object
 oHTTP = new ActiveXObject("Microsoft.XMLHTTP");
 if (oHTTP != null) {
  // specify callback for loading completion
  oHTTP.onreadystatechange = gotTarget;
  // open HTTP connection and send async request
  oHTTP.open('GET', sURL, true);
  oHTTP.send();
 }
 else {
  document.all['spnError'].innerText 
   = 'ERROR: Cannot create XMLHTTP object to load next page';
 }
}

function gotTarget() {
 // see if loading is complete
 if (oHTTP.readyState == 4) {
  // check if there was an error
  if (oHTTP.status == 200) {
   // dump next page content into this page
   document.write(oHTTP.responseText);
  }
  else {
   document.all['spnError'].innerText 
    = 'ERROR: Cannot load next page';
  }
 }
}
//-->

Information on the XMLHTTP Object

You can find a full reference to the XMLHTTP object (effectively the XMLHTTPRequest interface) in the MSDN library, at http://msdn.microsoft.com/library/en-us/xmlsdk30/htm/xmobjxmlhttprequest.asp.

One interesting point about this listing is in the gotTarget callback handler. After you've extracted the complete content of the new page as a string, you simply write it into the current browser window, using the client-side document.write method. This replaces the current content, giving the same output as in the first example in this chapter, after the main customer lookup process has completed (refer to Figure 3.5).

What you've actually achieved here is to reload the same page again in the background, while still at Stage 2 of the process (displaying the "please wait" message and progress bar) and then use it to replace the current page. But because the URL you request contains the customer ID in the query string this time, the new page generated by the server will be the one for Stage 3 of the process (containing the DataGrid control, populated with the results of the database search). Altogether, this is a neat and interesting solution!

The Changes to the HTML and Server Control Declarations in This Example

The only remaining features of this example that we need to examine are how to initiate the client-side code that loads the results page and how to handle cases where client-side scripting is disabled in the browser. In the HTML section of the page, you declare the <body> element as a server control this time, by adding an ID and the runat="server" attribute—just as you did for the <meta> element earlier in this chapter:

<body id="tagBody" runat="server">

Then, in the Page_Load event handler, you can add an appropriate onload attribute to the opening <body> tag in the server-side code. Listing 3.6 shows the changed section of the Page_Load event handler. The only section that differs in this example from the first example is the part where the postback from Stage 1 occurs—where you are generating the "please wait" page for Stage 2 of the process.

Listing 3.6 The Page_Load Event Handler for the Progress Bar Example

If Page.IsPostback Then

 Dim sRefreshURL As String = Request.Url.ToString() _
  & "?custID=" & txtCustomer.Text

 ' if it's IE, need to load new page using script because
 ' the META REFRESH prevents the animated GIF working
 If Request.Browser.Browser = "IE" Then
  tagBody.Attributes.Add("onload", "loadTarget('" _
                  & sRefreshURL & "');")

  ' set META REFRESH as well in case script is disabled
  ' use long delay so script can load page first if possible
  mtaRefresh.Attributes.Add("http-equiv", "refresh")
  mtaRefresh.Attributes.Add("content", "30;url=" & sRefreshURL)

 Else

  ' not IE so use META REFRESH to start loading next page
  ' allow 3 seconds for progress bar image to load
  mtaRefresh.Attributes.Add("http-equiv", "refresh")
  mtaRefresh.Attributes.Add("content", "3;url=" & sRefreshURL)

 End If

 frmMain.Visible = False
 divWait.Visible = True

Else
...

You use the ASP.NET Request.Browser object, which exposes a property also named (rather confusingly) Browser. This property indicates the browser type, and if it is "IE", you know that you are serving to an Internet Explorer browser—so we can add the onload attribute to the <body> element by using the Attributes collection of the HtmlGenericControl class that implements it in ASP.NET. The result, when viewed in the browser, looks like this:

<body id="tagBody" onload="loadTarget('/daveandal/books/6744
/loadwait/progressbar.aspx?custID=a');">

You also add a "catch all" feature in case scripting is disabled, by setting the attributes of the <meta> element. In this case, the <meta> element will cause a page reload after 30 seconds. You can also see in Listing 3.6 the changed value of the content attribute that you apply for non–Internet Explorer browsers, to allow the progress bar graphic to load before the redirection commences (as discussed earlier in this chapter).

Checking for the Version of Internet Explorer

In theory, you should test for the browser version as well as the type because the XMLHTTP object is available only in version 5 and higher of Internet Explorer. However, the "catch all" you build in for when scripting is disabled will also make the page work (after a fashion) on earlier versions of Internet Explorer. Whether anyone is still using version 4 or earlier, with all the security issues inherent in those versions, is open to discussion.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020