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

Another Simple Wait Page

Rate me:
Please Sign up or sign in to vote.
4.50/5 (7 votes)
11 Oct 2006CPOL2 min read 75.1K   716   56   14
An article to demonstrate to use asynchronous delegate call and client script callback to build long wait page

Sample Image - screenshot.jpg

Introduction

Sometime you need to process a lengthy job in your web form. It is a better idea to build a wait page instead of letting your user just stare at the screen doing nothing.

Background

There are a lot of solutions over Internet to accomplish this purpose. My solution isn't new, the initial idea is from Brian Dunnington's article Building a Better Wait Page in code project. I have been using this approach for long time in ASP.NET 1.1. Since the release of ASP.NET 2.0, Microsoft makes a lot easier to implement client side callback, I decided to expand this solution to include AJAX function, so that we don't need to refresh the page from time to time.

Using the code

There are 3 main areas you need to consider in this solution

  • Asynchronous delegate call
  • Hook up with client callback
  • Client script

Asynchronous delegate call

C#
/// <summary>
/// Definition of delegate
/// </summary>
/// <param name="minute"></param>
/// <returns></returns>
private delegate bool DoJobDelegate (int minute);

/// <summary>
/// To invoke the long process function
/// </summary>
/// <param name="minute"></param>
/// <returns></returns>
private IAsyncResult DoJobAsync(int minute) {
    DoJobDelegate doDelegate = new DoJobDelegate(doLongJob);
    IAsyncResult ar = doDelegate.BeginInvoke(minute,
                      new AsyncCallback(MyCallback), null);
    return ar;
}

/// <summary>
/// The server side callback handler
/// </summary>
/// <param name="ar"></param>
private void MyCallback (IAsyncResult ar) {
    AsyncResult aResult = (AsyncResult)ar;
    DoJobDelegate doDelegate = (DoJobDelegate)aResult.AsyncDelegate;
    // Session object is used to tell if process finishes or not
    Session["NewOrderResult"] = doDelegate.EndInvoke(ar);
}

/// <summary>
/// The main function to run long process
/// </summary>
/// <param name="minute"></param>
/// <returns></returns>
private bool doLongJob (int minute) {
    System.Threading.Thread.Sleep(minute * 1000 * 60);
    if (minute % 2 == 0) {
        return true;
    } else {
        return false;
    }
}

Hook up with client callback

In order to hook with client callback, you have to implement ICallbackEventHandler interface

C#
public partial class Process : System.Web.UI.Page, ICallbackEventHandler {
 protected string CallBackEventReference;
...
}

Then we need to prepare script to reference client function

C#
string ScriptRef = this.ClientScript.GetCallbackEventReference(
this,
"'CheckStatus'",
"ClientCallBack",
"this",
"ClientCallBack",
true);

CallBackEventReference = ScriptRef;

This will create a client function like WebForm_DoCallback('__Page','CheckStatus',ClientCallBack,this,ClientCallBack,true);

From this point, you need to implement 2 functions of this interface

C#
/// <summary>
/// Capture the event argument in this field, in this case I don't use it.
/// </summary>
string eventArgument = "";

/// <summary>
/// Returns result to client side
/// </summary>
/// <returns></returns>
string ICallbackEventHandler.GetCallbackResult() {
    if (Session["NewOrderResult"] != null) {
        // after async call finishes,
        // it sets this Session object to some value,
        // this method will capture the status
        if (Convert.ToBoolean(Session["NewOrderResult"])) {
            return "even.htm";
        } else {
            return "odd.htm";
        }
    } else {
        return "";
    }
}

/// <summary>
/// Gets parameter passed from client side
/// </summary>
/// <param name="eventArgument"></param>
void ICallbackEventHandler.RaiseCallbackEvent (string eventArgument) {
    this.eventArgument = eventArgument;
}

Client script

On the client side, we need to prepare some javascript functions with talk with server.

JavaScript
function ClientCallBack(Result, Context) {
    if (Result != "") {
        window.location.href = Result;
    }
}

In order to make broswer to check server process status, we also need a timer to make client script to run at some certain interval.

HTML
<body onload="startClock();">
JavaScript
// check server every 5 seconds, adjust this value to your own preference
var interval = 5
var x = interval
function startClock(){
    x = x - 1;
    setTimeout("startClock()", 1000);
    if(x == 0){
       <%= this.CallBackEventReference %>

So what is happnening now? The client script will be triggered every 5 seconds to talk with server. And ICallbackEventHandler.GetCallbackResult() method on server side will be called every 5 seconds. In this method it checks Session object value, if asynchronous call finishes the process, it will call the MyCallback to set Session object to a not null value returned from process result to make ICallbackEventHandler.GetCallbackResult() be able to capture the result.

Points of Interest

My first explore of client callback, I hope to add more features later.

History

  • 2006-10-11 Initial version.

License

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


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

Comments and Discussions

 
GeneralIs it possible to use this in a wizard Pin
D.Sridhar5-May-08 8:26
D.Sridhar5-May-08 8:26 
GeneralRe: Is it possible to use this in a wizard Pin
Hardy Wang5-May-08 8:37
Hardy Wang5-May-08 8:37 
Generalthe job is load a new page Pin
jrmora7-Mar-08 5:02
jrmora7-Mar-08 5:02 
GeneralRe: the job is load a new page Pin
Hardy Wang7-Mar-08 6:07
Hardy Wang7-Mar-08 6:07 
QuestionSQL Server Session State Pin
Simon Byrne16-May-07 4:37
Simon Byrne16-May-07 4:37 
AnswerRe: SQL Server Session State Pin
Hardy Wang4-Jun-07 3:38
Hardy Wang4-Jun-07 3:38 
Generalbrowser back button Pin
Joaquin Luna9-Dec-06 10:36
Joaquin Luna9-Dec-06 10:36 
GeneralVB.net Pin
Papichulo.NET18-Oct-06 11:04
Papichulo.NET18-Oct-06 11:04 
GeneralRe: VB.net Pin
Christian Graus18-Oct-06 11:39
protectorChristian Graus18-Oct-06 11:39 
GeneralRe: VB.net Pin
Hardy Wang19-Oct-06 5:15
Hardy Wang19-Oct-06 5:15 
AnswerRe: VB.net Pin
Joaquin Luna8-Dec-06 11:33
Joaquin Luna8-Dec-06 11:33 
Well I've never used C# and I only started using Visual Basic last week, but I think I've got the wait page working under VB. Sorry if there are any bugs I didn't catch, I'm new to the whole 'making websites' business. Good Luck!

Here is the code for Default.aspx.vb

Imports System
Imports System.Data
Imports System.Configuration
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls


Partial Class defaultclass
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

End Sub


Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmit.Click
If Not Me.IsValid Then
Return
End If
End Sub


Private Min As Integer

Public ReadOnly Property Minute() As Integer
Get
Min = 0
Integer.TryParse(txtMinute.Text, Min)
Return Min
End Get
End Property

End Class








And here is the code for Process.aspx.vb

Imports System
Imports System.Data
Imports System.Configuration
Imports System.Collections
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls
Imports System.Runtime.Remoting.Messaging


Partial Class Process
Inherits System.Web.UI.Page
Implements ICallbackEventHandler

Protected CallBackEventReference As String
Private Delegate Function DoJobDelegate(ByVal minute As Integer) As Boolean
Dim eventArgument As String = ""


Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack And Not IsCallback Then
Session("NewOrderResult") = Nothing
Dim prevPage As defaultclass = PreviousPage
If prevPage IsNot Nothing Then
lMinute.Text = "Your request will finish in " & prevPage.Minute & " minute(s)."
setcallbackstring()
DoJobAsync(prevPage.Minute)
Else
Response.Redirect("default.aspx")
End If
End If
End Sub

Private Function DoJobAsync(ByVal minute As Integer) As IAsyncResult
Dim doDelegate As New DoJobDelegate(AddressOf dolongjob)
Dim ar As IAsyncResult = doDelegate.BeginInvoke(minute, New AsyncCallback(AddressOf mycallback), Nothing)
Return ar
End Function

Private Sub mycallback(ByVal ar As IAsyncResult)
Dim aResult As AsyncResult = ar
Dim doDelegate As DoJobDelegate = aResult.AsyncDelegate
Session("NewOrderResult") = doDelegate.EndInvoke(ar)
End Sub

Private Function dolongjob(ByVal seconds As Integer) As Boolean
System.Threading.Thread.Sleep(seconds * 1000)
If (seconds Mod 2 = 0) Then
Return True
Else
Return False
End If

End Function

Protected Sub setcallbackstring()
Dim ScriptRef As String = ClientScript.GetCallbackEventReference( _
Me, "'CheckStatus'", "ClientCallBack", "this", "ClientCallBack", True)

CallBackEventReference = ScriptRef
End Sub




Function GetCallbackResult() As String Implements ICallbackEventHandler.GetCallbackResult
If Session("NewOrderResult") IsNot Nothing Then
If Convert.ToBoolean(Session("NewOrderResult")) Then
Return "even.htm"
Else
Return "odd.htm"
End If
Else
Return ""
End If

End Function


Sub RaiseCallbackEvent(ByVal eventArgument As String) Implements ICallbackEventHandler.RaiseCallbackEvent
Me.eventArgument = eventArgument
End Sub

End Class



Joaquin Luna
Roanoke VA
Questionempty source files? Pin
alex_-_12-Oct-06 4:42
alex_-_12-Oct-06 4:42 
AnswerRe: empty source files? Pin
Hardy Wang12-Oct-06 4:46
Hardy Wang12-Oct-06 4:46 
GeneralThanks ! Pin
dapoussin12-Oct-06 2:19
dapoussin12-Oct-06 2:19 

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.