Another Simple Wait Page






4.50/5 (7 votes)
An article to demonstrate to use asynchronous delegate call and client script callback to build long wait page
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
/// <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
public partial class Process : System.Web.UI.Page, ICallbackEventHandler {
protected string CallBackEventReference;
...
}
Then we need to prepare script to reference client function
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
/// <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.
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.
<body onload="startClock();">
// 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.