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
private delegate bool DoJobDelegate (int minute);
private IAsyncResult DoJobAsync(int minute) {
DoJobDelegate doDelegate = new DoJobDelegate(doLongJob);
IAsyncResult ar = doDelegate.BeginInvoke(minute,
new AsyncCallback(MyCallback), null);
return ar;
}
private void MyCallback (IAsyncResult ar) {
AsyncResult aResult = (AsyncResult)ar;
DoJobDelegate doDelegate = (DoJobDelegate)aResult.AsyncDelegate;
Session["NewOrderResult"] = doDelegate.EndInvoke(ar);
}
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
string eventArgument = "";
string ICallbackEventHandler.GetCallbackResult() {
if (Session["NewOrderResult"] != null) {
if (Convert.ToBoolean(Session["NewOrderResult"])) {
return "even.htm";
} else {
return "odd.htm";
}
} else {
return "";
}
}
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();">
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.