Click here to Skip to main content
15,867,594 members
Articles / Web Development / ASP.NET

User Feedback For Long Running Tasks in ASP.NET

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
27 Apr 2012CPOL3 min read 28.2K   3   24   6
Giving a web page user regular indication of the progress of a server task

Introduction

The simple code snippets presented here are a solution to the problem of how to provide regular feedback to a user of an ASP.Net page whilst they are waiting for a long running task to complete on the server.

Background

This solution came about, as is often the case, in response to late changes in the requirements for a newly developed system. The system originally was a simple intranet page to display a report, with options to filter and sort the data on the report.

The late change was that the users requested the ability to save the underlying data as a series of xml documents on the file system, for offline use. Clearly if this had been known at the outset then the architecture of the solution may have been designed differently.

The problem became one of allowing the user to see that something was actually happening on the server, in a process that could take many minutes to complete. Options considered included just displaying progress bar, or hourglass, or firing off a the task asynchronously and expecting the user to refresh the page for updates. Niether of these were deemed totally satisfactory.

As a server task is unable to push status updates to the client (browser), the solution is to get the browser to request regular updates from the server.

In a nutshell, the solution chosen involves firing off the long running task asynchronously, and monitoring it on a separate thread initiated by browser requests.

In practice, the long running task writes progress updates to a shared area, and the web page makes regular requests to the server to read that shared area and display the progress to the user.

Using the code

A simplified version of the solution is shown below, in order to demonstrate the principles.

In summary, we have a web page, Default.aspx, on which there is a button which triggers the long running server task. The task is deployed server-side as a generic handler, ProcessTask.ashx.

Initiation of this handler takes place in Javascript fired when the button is clicked:

var tmrProgress;

 //SENDING XML
 function postSend() {
     var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

   divResponse.innerHTML = "";

     // 'true' specifies that it's a async call
     xmlhttp.Open("POST", "ProcessTask.ashx", true);

     // Register a callback for the async, call and display a completion message
     xmlhttp.onreadystatechange =
          function () {
             if (xmlhttp.readyState == 4) {
                 window.clearInterval(tmrProgress);
                 var response = xmlhttp.responseText;
                 divResponse.innerHTML += response;

         }
 }

  // Send the actual request
 xmlhttp.Send();
 tmrProgress = window.setInterval("showSendProgress();", 500);

 }

The Javascript fires off an asynchronous request to the handler, registers a callback for completion of the task, and initiates a timer which will request progress updates fromt the server.

For test purposes, the server task is simulating time taken for creation of files by means of a thread.sleep command. On "submission" of each file, a count is incremented and saved to the shared area, in this case the .NET cache is used.

Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

        Const NumberOfFilesToSend As Integer = 50

        context.Response.ContentType = "text/plain"

        Try

            For i As Integer = 1 To NumberOfFilesToSend

                'report the current status of the task to shared cache area
                context.Cache("FileSending") = i

                'simulate a time intensive task
                Threading.Thread.Sleep(100)
            Next

            context.Response.Write(String.Format("Finished sending {0} files", NumberOfFilesToSend))

        Catch ex As Exception
            context.Response.Write(String.Format("Error sending files: {0}", ex.Message))
        End Try

    End Sub

For progress reporting, the function showSendProgress() is called on the browser at 500ms intervals, triggered by the timer tmrProgress. This function calls a separate generic handler to get the current status from the server:

JavaScript
function showSendProgress() {
          var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

          // 'true' specifies that it's a async call
          xmlhttp.Open("POST", "GetTaskProgress.ashx", true);

          // Register a callback for the call
          xmlhttp.onreadystatechange =
              function () {
              if (xmlhttp.readyState == 4) {
                      var response = xmlhttp.responseText;
                      divResponse.innerHTML = "Processing File:  " + response;

              }
              }
          // Send the actual request
          xmlhttp.Send();
      }

Responses from handler GetTaskProgress.ashx are captured in the callback, and update the status on the page, in divResponse.

GetTaskProgress.ashx simply queries the cache and reports back to the client

VB.NET
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

     context.Response.ContentType = "text/plain"

     If Not HttpContext.Current.Cache("FileSending") Is Nothing Then
         context.Response.Write(HttpContext.Current.Cache("FileSending"))
     End If

 End Sub

Points of Interest

One point with the solution presented is that it is not accurately reporting on the exact status of the server task in real-time, it's just giving a regular indiction to the user that something is progressing. Some fine tuning of the refresh rate would be necessary depending of the duration of the task, as well as the frequency it updates it's own status.

.Net cache has been used as a simple shared area for simplicity's sake, but this could easily be changes to use session state, SQL server or any other shared area.

History

Version 1.0 27 April 2012

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Writer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionCache Pin
kiquenet.com20-Dec-19 22:09
professionalkiquenet.com20-Dec-19 22:09 
QuestionHola, vstudio 2012 project Pin
Hwong232326-May-13 4:58
Hwong232326-May-13 4:58 
QuestionDownlaod Pin
St.Kirchner4-Oct-12 4:21
St.Kirchner4-Oct-12 4:21 
GeneralNice article. Really helpful Pin
vijay reddy chennadi13-Jul-12 6:04
vijay reddy chennadi13-Jul-12 6:04 
GeneralMy vote of 5 Pin
Pankaj Nikam25-Jun-12 5:09
professionalPankaj Nikam25-Jun-12 5:09 
QuestionDownload link seems to have gone? Pin
wbartussek27-May-12 10:10
wbartussek27-May-12 10:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.