ASP.NET中的回调技术其实也是通过XMLHttpRequest来实现的,只不过微软做了进一步的封装,让我们在使用的过程中没有看到。
<%@ Page Language="C#" %>
<%@ Implements Interface="System.Web.UI.ICallbackEventHandler" %>
<%@ Import Namespace="System.Text" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>用户注册</title>
<script type="text/javascript" language="javascript">
//客户端执行的方法
//回调成功执行的回调函数,下面的方法是接收并处理服务器方法执行的返回结果
function Success(result, context) {
message.innerText = result;
alert("传递的额外信息是"+context.id);
}
//回调失败执行的回调函数,下面的方法是当接收服务器方法处理处理的结果发生异常时调用的方法
function Error(result, context) {
message.innerText = '发生了异常';
alert("传递的额外信息是" + context);
}
</script>
<script runat="server">
//定义在服务器端运行的方法
string result = "";
public void RaiseCallbackEvent(string eventArgument)//相当于delegate里面已经存在的函数
{
if (eventArgument.ToLower().IndexOf("admin") != -1)
{
result = eventArgument + "不能作为用户名注册";
//Response.Write("<sc"+"ript type='text/javascript' language='javascript'>alert('abc')</sc"+"ript>");
}
else
{
result = eventArgument + "可以作为用户名注册";
}
}
//定义返回回调方法执行结果的方法
public string GetCallbackResult()//相当于执行delegate的EndInvoke方法,得到返回值
{
return result;
}
//服务器上执行的方法
public void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
return;
//通过设置断点调试可知,在进行回调的时候,服务器其实也重新触发了Page_Load事件
//获取对当前页的ClientScriptManager的引用
ClientScriptManager csm = this.ClientScript;//在这里this可以省略
// 获取回调引用。会在客户端生成WebForm_DoCallback方法,调用它来达到异步调用。这个方式是微软写的方法,会被发送到客户端
//注意这里的"Success"和"Error"两个字符串分别客户端代码中定义的两个javascript函数
//args表示传递的参数,context表示可以传递的其他信息,也可以设置为空
//下面的方法最后一个参数的意义:true表示执行异步回调,false表示执行同步回调
//相当于Delegate中的BeginInvoke方法注册要回调的函数,而不是立即执行回调,注册形式比如(参数args,new AsyncCallback(回调函数new),上下文contest)
//执行完下面的语句后,reference = "WebForm_DoCallback('__Page',args,Success,context,Error,false)",
//自动生成的WebForm_DoCallback('__Page',args,Success,context,Error,false)就相当于回调,相当于delegate.BeginInvoke
string reference = csm.GetCallbackEventReference(this, "args", "Success","context", "Error", false);
string callbackScript = "function CallServerMethod(args,context){ " + reference + ";}";
//向当前页面注册JavaScript脚本代码
csm.RegisterClientScriptBlock(this.GetType(), "CallServerMethod", callbackScript, true);
//生成的callbackScript = "function CallServerMethod(args,context) { WebForm_DoCallback('__Page',args,Success,context,Error,false);}"
//可以看出callbackScript代码实际上是一个调用WebForm_DoCallback回调的函数,注意WebForm_DoCallback是回调,不是回调函数
//在客户端要进行要进行某个操作时(在此程序中表示当用户名文本框失去焦点之后)激发CallServerMethod这个客户端方法,
//这个客户端方法是由在Page_Load时由asp.net动态生成的,并向其传递需要的参数args,也可以传递上下文环境参数context,
//args是必选参数,context是可选参数,可用于传递其他信息,是object类型,甚至可以传递this.id或this等,如果没有传递context,则传递null
//然后将CallserverMethod(args,context)中的args参数传递给WebForm_DoCallback('__Page',args,Success,context,Error,false)
//中的args(注:WebForm_DoCallback中的Success和Error脚本函数都是在页面第一次初始化的时候就绑定了的),
//再传递给服务器端的RaiseCallbackEvent(string args)中的args,从而调用服务器端的RaiseCallbackEvent函数,
//RaiseCallbackEvent执行完毕后,自动执行服务器端的GetCallbackResult函数,执行完毕之后,
//如果没有异常,就自动执行客户端的Success回调函数(回调成功时调用)
//如果出现异常,则执行客户端的Error回调函数(回调失败时调用)
//我认为Success和Error才是回调函数,WebForm_DoCallback('__Page',args,Success,context,Error,false)只是回调
//上面提到的context相当于IAsyncResult.AsyncState,可以在Success和Error函数中捕获,可以用于传递其它的相信
//有时候可以用来区别多个回调
//可是WebForm_DoCallback函数在哪里呢?其实在第一次初始化页面的时候服务器传给客户端的html代码引入如下脚本
//<script src="/WebResource.axd?d=CcZ-_AaHZnD65xnNHEUijg2&t=633578466781093750" type="text/javascript" />
//说明在第一次执行Page_Load的时候服务器就自动生成了一个js文件,里面含有很多的JavaScript脚本函数
//比如function WebForm_DoCallback(eventTarget, eventArgument, eventCallback, context, errorCallback, useAsync){}
//函数就在该js代码中
//实际上在第一次Page_Load的时候已经生成了三个东西
//(1)第一部分
//这部分是因为form具有runat="server",自动生成的回发函数,通过theForm.submit()来实现
/*<script type="text/javascript">
<!--
var theForm = document.forms['form1'];
if (!theForm) {
theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
<script>*/
//(2)第二部分
//<script src="/WebResource.axd?d=CcZ-_AaHZnD65xnNHEUijg2&t=633578466781093750" type="text/javascript"><script>
//这部分代码是用来生成一些用于Ajax调用的js脚本。说穿了,asp.net之所以开发起来方便,是因为微软在幕后默默地为我们做了很多工作,回调的本质其实就是Ajax调用。
/*(3)第三部分
<script type="text/javascript">
<!--
function CallServerMethod(args, context) {
WebForm_DoCallback('__Page',args,Success,context,Error,false);
}
<script>
这部分代码是后台生成的,通过获取Page类的ClientScript属性,也就是ClientScriptManager的实例注册到页面的,里面定义了两个javascript函数:CallServerMethod函数和WebForm_DoCallback函数,并且是在CallServerMethod函数中调用WebForm_DoCallback函数。
}*/
/*(4)第四部分
<script type="text/javascript">
<!--
WebForm_InitCallback();// -->
<script>
这部分代码也是幕后生成的,这个javascript函数也可以在那个axd文件中找到。*/
}
</script>
</head>
<body>
<form id="form1" runat="server">
<table border="1" cellpadding="0" cellspacing="0" width="400px">
<tr>
<td width="100px">用户名</td><td><input type="text" size="10" maxlength="20" id="txtUserName" οnblur="CallServerMethod(txtUserName.value,this)" /><span id="message"></span></td>
</tr>
<tr>
<td>密码</td><td><input type="password" size="10" maxlength="20" id="txtPwd" /></td>
</tr>
</table>
</form>
</body>
</html>
待续...