ASP.NET中的回调技术(CallBack)
在asp.net中客户端与服务器端的交互默认都是整页面提交,此时客户端将当前页面表单中的数据(包括一些自动生成的隐藏域)都提交到服务器端,服务器重新实例化一个当前页面类的实例响应这个请求,然后将整个页面的内容重新发送到客户端,这种处理方式对运行结果没什么影响,不过这种方式加重了网络的数据传输负担、加大了服务器的工作压力,并且用户还需要等待最终处理结果。
假如是我们希望有这么一个功能,当用户填写完用户名之后就检查服务器数据库里是否已存在该用户名,如果存在就给出已经存在此用户名的提示,如果不存在就提示用户此用户名可用,对于这种情况其实只需要传递一个用户名作为参数即可,上面的做法却需要提交整个表单,有点小题大做。
解决上面的问题的办法目前主流做法有三种:纯javascript实现、微软Ajax类库实现还有用AjaxPro实现。这里用另外一种实现:通过回调技术。
实现回调技术需要以下步骤:
(1)让当前页面实现ICallbackEventHandler接口,这个接口定义了两个方法:
string GetCallbackResult()方法和void RaiseCallbackEvent (string eventArgument)方法。其中GetCallbackResult ()方法的作用是返回以控件为目标的回调事件的结果,RaiseCallbackEvent()方法的作用是处理以控件为目标的回调事件。
(2)为当前页提供三个javascript客户端脚本函数。一个javascript函数用于执行对服务器的实际请求,在这个函数中可以提供一个字符串类型的参数发送到服务器端;另一个javascript函数用于接收服务器端方法的执行后返回的字符串类型结果,并处理这个结果;还有一个是执行对服务器请求的帮助函数,在服务器代码中通过GetCallbackEventReference()方法获取这个方法的引用时由asp.net自动生成这个函数。
1、实现ICallbackEventHandler
2、实现接口中的方法:RaiseCallbackEvent
3、实现接口中的方法:GetCallbackResult
方法 |
解释 |
参数 |
void RaiseCallbackEvent(string eventArgument) | 返回处理以控件为目标的回调事件 | 表示要传递到事件处理程序的事件参数 |
string GetCallbackResult() | 返回以控件为目标的回调事件的结果 |
下面我以一个详细的例子来讲述如何使用回调,用Dreamweaver创建一个Register. aspx页面,代码如下:
<%@ 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>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>用户注册</title>
<script language="javascript">
//客户端执行的方法
//下面的方法是接收并处理服务器方法执行的返回结果
function Success(args, context)
{
message.innerText = args;
}
//下面的方式是当接收服务器方法处理的结果发生异常时调用的方法
function Error(args, context)
{
message.innerText = '发生了异常';
}
</script>
<script language="c#" runat="server">
string result="";
// 定义在服务器端运行的回调方法.
public void RaiseCallbackEvent(String eventArgument)
{
//把输入的与admin作比较,如果要检索的字符串值没有出现(也就是说不等于admin),则该方法返回 -1
if(eventArgument.ToLower().IndexOf("admin")!=-1)
{
result=eventArgument+"不能作为用户名注册。";
}
else
{
result=eventArgument+"可以注册。";
}
//throw new Exception();
}
//定义返回回调方法执行结果的方法
public string GetCallbackResult()
{
return result;
}
//服务器上执行的方法
public void Page_Load(Object sender,EventArgs e)
{
// 获取当前页的ClientScriptManager的引用
ClientScriptManager csm = Page.ClientScript;
// 获取回调引用。会在客户端生成WebForm_DoCallback方法,调用它来达到异步调用。这个方式是微软写的方法,会被发送到客户端
//注意这里的"Success"和"Error"两个字符串分别客户端代码中定义的两个javascript函数
//下面的方法最后一个参数的意义:true表示执行异步回调,false表示执行同步回调
String reference = csm.GetCallbackEventReference(this, "args","Success","","Error",false);
String callbackScript = "function CallServerMethod(args, context) {\n" + reference + ";\n }";
// 向当前页面注册javascript脚本代码
csm.RegisterClientScriptBlock(this.GetType(), "CallServerMethod", callbackScript, true);
}
</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"
onblur="CallServerMethod(txtUserName.value,null)" />
<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>
几点说明:(1)
这句表示当前页面实现了ICallbackEventHandler接口,如果采用页面与代码分离的模式,后台cs代码则应是:
{
//cs代码
}
(2)
这里有一个onblur="CallServerMethod(txtUserName.value,null),表示当用户名文本框失去焦点之后激发CallServerMethod这个客户端方法,这个客户端方法是由asp.net动态生成的。
(3)
中的"Success"和"Error"分别代表客户端的javascript函数,可以在代码中见到,其中"Success"代表调用服务器端方法成功后要执行的客户端方法名,"Error"代表调用服务器端方法失败时调用的客户端方法名。
该页面在客户端生成的HTML代码如下:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>用户注册</title>
<script type="text/javascript" language="javascript">
//客户端执行的方法
//下面的方法是接收并处理服务器方法执行的返回结果
function Success(args, context)
{
message.innerText = args;
}
//下面的方式是当接收服务器方法处理的结果发生异常时调用的方法
function Error(args, context)
{
message.innerText = '发生了异常';
}
</script>
</head>
<body>
<form method="post" action="Register.aspx" id="form1">
<div class="aspNetHidden">
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNzgzNDMwNTMzZGTZBYZOkBnHYrPqZwDocykE9kF/SOSZotkAOjqOBzODgg==" />
</div>
<script type="text/javascript">
//<![CDATA[
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>
<script src="/Web/WebResource.axd?d=RAo7rL6tKkHnPnQX99wyRg2&t=634095114802094502" type="text/javascript">
</script>
<script type="text/javascript">
//<![CDATA[
function CallServerMethod(args, context) {
WebForm_DoCallback('__Page',args,Success,"",Error,true);
}//]]>
</script>
<table border="1" cellpadding="0" cellspacing="0" width="400px">
<tr>
<td width="100px">用户名</td><td><input type="text" size="10" maxlength="20" id="txtUserName"
</tr>
<tr>
<td>密码</td><td><input type="password" size="10" maxlength="20" id="txtPwd" /></td>
</tr>
</table>
<script type="text/javascript">
//<![CDATA[
WebForm_InitCallback();//]]>
</script>
</form>
</body>
</html>
在生成的HTML代码中多了几段javascipt代码块,下面分别说明:
(1)第一部分
//<![CDATA[
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>
这部分代码是每个asp.net页面发送到客户端都会生成的,用于提交当前表单,其中eventTarget参数表示激发提交事件的控件,eventArgument参数表示发生该事件时的参数信息。
(2)第二部分
</script>
这部分代码是用来生成一些用于Ajax调用的js脚本。实际上asp.net之所以开发起来方便,是因为微软在幕后默默地为我们做了很多工作,回调的本质其实就是Ajax调用。 可以将WebResource.axd?d=RAo7rL6tKkHnPnQX99wyRg2&t=634095114802094502" 复制到地址栏上,如图:
回车后弹出一个文件下载框如下图所示:
将这个页面保存到本地,虽然默认的保存文件的后缀为“.axd”,但它其实是一个文本文件,里面是一些javascript代码,可以用记事本打开,在里面我们可以看到“WebForm_DoCallback”这个方法,如下:
在这个axd文件里做了很多幕后工作,所以我们的回调才相对比较简单。
(3))第三部分
//<![CDATA[
function CallServerMethod(args, context) {
WebForm_DoCallback('__Page',args,Success,"",Error,true);
}//]]>
</script>
这部分代码是后台生成的,通过获取Page类的ClientScript属性,也就是ClientScriptManager的实例注册到页面的,里面定义了两个javascript函数:CallServerMethod函数和WebForm_DoCallback函数,并且是在CallServerMethod函数中调用WebForm_DoCallback函数。
(4)第四部分
//<![CDATA[
WebForm_InitCallback();//]]>
</script>
这部分代码也是幕后生成的,这个javascript函数也可以在那个axd文件中找到。