To implement the script callback framework in ASP.Net 1.1, we need the following things:
1. The ICallbackEventHandler.
2. The Page that has incorporated the script callback feature.
3. The client side script for call back.
The interface ICallbackEventHandler is simple:
using System;
namespace ClientPopUp
{
// This interface must be implemented by any control or page that needs postback.
public interface ICallbackEventHandler
{
string RaiseClientCallbackEvent(string eventArgument);
}
}
The page can inherit from “System.Web.UI.Page”:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace ClientPopUp
{
public class CallbackPage : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// __CALLBACKID will be in the Request dictionary with script callback.
if (Request["__CALLBACKID"] != null)
{
_isCallback = true;
handleCallback();
}
}
private void handleCallback()
{
// Get the UniqueID of the control.
// I have not tested this with controls put in INamingContainer.
// It may not work properly.
Control _control;
string controlUniqueID = Request["__CALLBACKID"];
if (controlUniqueID == "__PAGE")
{
_control = this;
}
else
{
_control = FindControl(controlUniqueID);
}
// Get the reference to the interface.
ICallbackEventHandler callbackHandler = _control as ICallbackEventHandler;
if (callbackHandler != null)
{
Response.Clear();
string result;
try
{
// Fire the callback handler method.
result = callbackHandler.RaiseClientCallbackEvent(Request["____CALLBACKPARAM"]);
// 's' for success.This will be further processed at client side.
Response.Write('s');
}
catch (Exception ex)
{
// 'e' for Exception.
Response.Write('e');
result = ex.Message;
}
// Write back to client.
Response.Write(result);
// Avoid any caching at client side.
Response.Cache.SetExpires(DateTime.Now);
Response.End();
}
}
// Is client script callback?
private bool _isCallback = false;
public bool IsCallback
{
get {return _isCallback;}
}
// JavaScript file contains the client callback functions
private const string CALLBACKSCRIPT_KEY = "Callback.js";
// Get the client side callback JavaScript function name.
// Then we can attach the function to any client side events.
public string GetCallbackEventReference(
Control _control, // Target control that handles callback at server side.
string argument, // String argument.
string clientCallback, // Client side callback function to process the result.
// Usually this function operates DOM.
string context, // Optional context.
string clientErrorCallback, // Optional client side error handler.
bool useAsync // Sync or Async ?
)
{
string target;
if (_control is ICallbackEventHandler)
{
if (_control is Page)
{
target = "__PAGE"; // Page needs special handling.
}
else
{
target = _control.UniqueID;
}
}
else
{
throw new ArgumentException("The control must implement ICallbackEventHandler interface.");
}
if ((clientCallback == null) || (clientCallback == string.Empty))
{
throw new ArgumentException("The clientCallback argument cannot be null or empty");
}
if (((Request != null)) && Request.Browser.JavaScript)
{
// Register the callback initialization scripts.
if (!IsClientScriptBlockRegistered("CallbackInitializationScript"))
{
RegisterClientScriptBlock("CallbackInitializationScript",
String.Format("<script language=JavaScript src=\"{0}/scripts/{1}\" type=\"text/javascript\"></script>", Request.ApplicationPath, CALLBACKSCRIPT_KEY));
}
if (!IsStartupScriptRegistered("PageCallbackScript"))
{
RegisterStartupScript("PageCallbackScript", "<script language=JavaScript>var pageUrl='" + Request.Url.PathAndQuery + "';\r\n WebForm_InitCallback();</script>");
}
}
else
{
throw new NotSupportedException("Browser does not support JavaScript?");
}
if (argument == null)
{
argument = "null";
}
else if (argument.Length == 0)
{
argument = "\"\"";
}
if (context == null)
{
context = "null";
}
else if (context.Length == 0)
{
context = "\"\"";
}
// Constructor the client side callback function reference.
string[] textArray1 = new string[13] { "WebForm_DoCallback('", target, "',", argument, ",", clientCallback, ",", context, ",", (clientErrorCallback == null) ? "null" : clientErrorCallback, ",", useAsync ? "true" : "false", ")" } ;
return string.Concat(textArray1);
}
}
}
The client side callback script can be the most difficult part but we can borrow it from ASP.Net 2.0:
// Global callback object. It seems that this cannot process simultaneous Async callbacks.
var __callbackObject = new Object();
function WebForm_DoCallback(eventTarget, eventArgument, eventCallback, context, errorCallback, useAsync) {
re = new RegExp("\\x2B", "g");
var postData = __theFormPostData +
"__CALLBACKID=" + eventTarget +
"&__CALLBACKPARAM=" + escape(eventArgument).replace(re, "%2B");
// For non MS browsers, we can use the "XMLHttpRequest" object.
if (__nonMSDOMBrowser) {
var xmlRequest = new XMLHttpRequest();
if (pageUrl.indexOf("?") != -1) {
xmlRequest.open("GET", pageUrl + "&" + postData, false);
}
else {
xmlRequest.open("GET", pageUrl + "?" + postData, false);
}
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlRequest.send(null);
response = xmlRequest.responseText;
if (response.charAt(0) == "s") {
if (eventCallback != null) {
eventCallback(response.substring(1), context);
}
}
else {
if (errorCallback != null) {
errorCallback(response.substring(1), context);
}
}
}
// For IE, we use XMLHTTP.
else {
var xmlRequest = new ActiveXObject("Microsoft.XMLHTTP");
// Hook the readystatechange event.
xmlRequest.onreadystatechange = WebForm_CallbackComplete;
__callbackObject.xmlRequest = xmlRequest;
__callbackObject.eventCallback = eventCallback;
__callbackObject.context = context;
__callbackObject.errorCallback = errorCallback;
var usePost = false;
// POST or use URL query string?
if (pageUrl.length + postData.length + 1 > 2067) {
usePost = true;
}
if (usePost) {
xmlRequest.open("POST", pageUrl, useAsync);
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlRequest.send(postData);
}
else {
if (pageUrl.indexOf("?") != -1) {
xmlRequest.open("GET", pageUrl + "&" + postData, useAsync);
}
else {
xmlRequest.open("GET", pageUrl + "?" + postData, useAsync);
}
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlRequest.send();
}
}
}
function WebForm_CallbackComplete() {
if (__callbackObject.xmlRequest.readyState == 4) {
response = __callbackObject.xmlRequest.responseText;
// Success or Exception from the server side?
if (response.charAt(0) == "s") {
if (__callbackObject.eventCallback != null) {
// Invoke the client side callback function to manipulate DOM.
__callbackObject.eventCallback(response.substring(1), __callbackObject.context);
}
}
else {
if (__callbackObject.errorCallback != null) {
__callbackObject.errorCallback(response.substring(1), __callbackObject.context);
}
}
}
}
var __nonMSDOMBrowser = (window.navigator.appName.toLowerCase().indexOf('explorer') == -1);
var __theFormPostData = "";
var theForm = document.forms[0];
function WebForm_InitCallback() {
count = theForm.elements.length;
var element;
re = new RegExp("\\x2B", "g");
// Prepare the FORM data we will send to the server.
for (i = 0; i < count; i++) {
element = theForm.elements[i];
if (element.tagName.toLowerCase() == "input") {
__theFormPostData += element.name + "=" + element.value.replace(re, "%2B") + "&";
}
else if (element.tagName.toLowerCase() == "select") {
selectCount = element.children.length;
for (j = 0; j < selectCount; j++) {
selectChild = element.children[j];
if ((selectChild.tagName.toLowerCase() == "option") && (selectChild.selected == true)) {
__theFormPostData += element.name + "=" + selectChild.value.replace(re, "%2B") + "&";
}
}
}
}
}
That’s all. The following is a test page. For more information about the callback framework, please refer to the document on ASP.Net 2.0.
<%@ Page language="c#" Inherits="ClientPopUp.CallbackPage" %>
<%@ Implements Interface="ClientPopUp.ICallbackEventHandler" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm1</title>