早在ASP.NET2.0 bate 1时就已经包含一个异步技术叫"Callback",它是通过前端Client端向后端服务器传送参数数据,服务器再以接收到的参数进行查询处理,最后将结果回传给前端显示结果.而这样的过程似乎有点不可思意(虽非创举),若您以JavaScript(Client端)或ASP.NET(Server端)的二分法观念来思考是无法理解的,因为JavaScript内存管理空间和.NET CLR内存管理是不同的进程空间,可以说老死不相往来各管各的,彼此无法直接参照亦没有可直接沟通的方式,而Callback却是实践俩种系统,(Client端与Server端)能够沟通的方式之一,因为他是由前端触发,所以他的名称就叫Client-Callback.

例一 使用Callbacj进行异步数据库查询
本范例将通过前端Callback传送"FirstName"员工姓名,而后端ASP.NET以此FirstName为参数,以ADO.NET方式向北风数据库查询是否有符合的员工数据,若有符合者则返回该员工基本资料,若无则回传查无此人消息,请参考ClientCallbacks.aspx程序,步骤说明如下.
STEP1 :确认北风数据库中Employees数据表的存在
STEP2 :建立Client端JavaScript及HTML对象
Client端JavaScdript及HTML对象程序如下:

Code
<head runat="server">
<title>使用Callback进行异步数据库查询</title>
<script type="text/JavaScript">
function DoSearch()
{
var txtFirstName = document.getElementById("txtUserName");
CallServer(txtFirstName.value, "");
}
function ReceiveServerData(txtUserInfo)
{
Results.innerText = txtUserInfo;
}
setInterval('DoSearch()',1000);
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
姓名:<input id = "txtUserName" type = "text" /><br />
<span id= "Results" style ="background-color:pink;width:500px;"></span>
</div>
</form>
</body>
什么时候ASP.NET查询数据库连BUTTON按钮都可以不需要.那将如何触发服务器程序查询员工数据?为了让大家更彻底体验lient-Callback异步的威力于作用,在此可以拿掉了Button控件,改以JavaScript来定时查询,各位才能清楚的认识到什么是Client-Callback
STEP3 :在Server端动态注册JavaScript
以下是在Server端动态注册JavaScript,其用途是供上一步骤的JavaScript传如参数,再真正进行Callback调用后端ASP.NET程序,程序如下:

Code
protected void Page_Load(object sender, EventArgs e)
{
//动态注册JavaScript
String cbReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context");
String callbackScript;
callbackScript = "function CallServer(arg, context)" + "{ " + cbReference + "} ;";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "CallServer", callbackScript, true);
}
STEP4 :实现ICallbackEventHandler,并实现IcallbackEventHandler的俩种方法:RaiseCallbackEvent()及GetCallbackResult().程序如下;

Code
public partial class ClientCallbacks : System.Web.UI.Page,ICallbackEventHandler
{
protected string txtUserInfo; //用户基本信息
protected void Page_Load(object sender, EventArgs e)
{
//动态注册JavaScript
//获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的控件、参数、客户端脚本和上下文
String cbReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context");
String callbackScript = "function CallServer(arg, context)" + "{ " + cbReference + "} ;";
//将JavaScript区块添加页面顶端。您可以字符串形式创建这些代码,然后将它传递给添加网页的方法。您可以使用这种方法任何JavaScript插入网页
//(类型,键,脚本文本,指示是否注册)
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "CallServer", callbackScript, true); //注册脚本
}
//引发Callback事件处理
public void RaiseCallbackEvent(string txtFirstName)
{
if (txtFirstName != null)
{
//SqlConnection conn = new SqlConnection("data source = .;initial catalog= Northwind;user id = sa;password = sa");
SqlConnection conn = new SqlConnection("data source=.;initial catalog=Northwind;user id=sa;password=sa");
conn.Open();
SqlCommand cmd = new SqlCommand("select EmployeeID,FirstName,City,Address from Employees where FirstName = @FirstName", conn);
cmd.Parameters.Add("@FirstName", SqlDbType.NVarChar, 10).Value = txtFirstName;
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
txtUserInfo = "员工代号:" + dr["EmployeeID"] + " ,";
txtUserInfo += "姓名:" + dr["FirstName"] + " ,";
txtUserInfo += "居住城市:" + dr["City"] + " ,";
txtUserInfo += "地址" + dr["Address"].ToString().Replace("\r\n", "") + " ,";
txtUserInfo += "服务器查询时间: " + DateTime.Now.ToLongTimeString();
}
else
{
if (String.IsNullOrEmpty(txtFirstName))
{
txtUserInfo = "请输入姓名";
}
else
{
txtUserInfo = "查无此人!";
}
}
cmd.Dispose();
cmd.Dispose();
cmd.Dispose();
}
}
//回传Callback 结果
public string GetCallbackResult()
{
return txtUserInfo;//返回员工基本信息
}
}
最后再简要的说明一下流程 PageLoad之后 开始客户端开始执行SetInterval()函数->DoSearch()->CallServer(此时CallServer已经在PageLoad的时候完成注册)->Callback(执行2个接口指定的方法)->ReceiceServerData----
例二 使用Callback进行异步数据库查询(简化版)
上面的范例有些复杂,下面去掉一些JavaScript及动态注册,使得程序更容易理解
Client端(ClientCallbackSimple.aspx)
以下是前端的HTML代码

Code
<head runat="server">
<title>无标题页</title>
<script type="text/JavaScript">
function OnCallback(txtUserInfo,context)
{
document.getElementById("Results").innerText = txtUserInfo;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
姓名
<input id="txtUserName" type="text" />
<input id="btnCallback" type="button" value="Callback" onclick=
"<%= ClientScript.GetCallbackEventReference(this,"document.getElementById'txtUserName').value","OnCallback",null) %>" />
<br />
<div id="Results" style="background-color: pink">
</div>
</div>
</form>
</body>
程序说明:Client端程序重点浓缩道个,一个是funciton OnCallback(),另一个是button的onclick事件
Server端 (ClientCallbacksSimple.aspx.cs)

Code
public partial class ClientCallbacksSimple : System.Web.UI.Page,System.Web.UI.ICallbackEventHandler
{
protected string txtUserInfo;//用户基本信息
protected void Page_Load(object sender, EventArgs e)
{
}
//引发Callback事件处理
public void RaiseCallbackEvent(string txtFirstName)
{
txtUserInfo = txtFirstName;
if (txtFirstName != null)
{
SqlConnection conn = new SqlConnection("data source = .;initial catalog = Northwind;User id = sa;password = sa");
conn.Open();
SqlCommand cmd = new SqlCommand("Select EmployeeID,FirstName,City,Address from Employees where FirstName = @FirstName", conn);
cmd.Parameters.Add("@FirstName", SqlDbType.NVarChar, 10).Value = txtFirstName;
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
txtUserInfo = "员工代号:" + dr["EmployeeID"] + "\r\n";
txtUserInfo += "姓名:" + dr["FirstName"] + "\r\n";
txtUserInfo += "居住城市:" + dr["City"] + "\r\n";
txtUserInfo += "地址:" + dr["Address"].ToString().Replace("\r\n", "");
txtUserInfo += "服务器查询时间" + DateTime.Now.ToString();
}
else
{
if (String.IsNullOrEmpty(txtFirstName))
{
txtUserInfo = "请输出姓名";
}
else
{
txtUserInfo = "查无此人";
}
}
cmd.Dispose();
dr.Dispose();
conn.Dispose();
}
}
//回传Callback结果
public string GetCallbackResult()
{
return txtUserInfo;//返回员工基本信息
}
}
程序说明:在Server端拿掉了一堆看不懂的JavaScript,里面剩下的都是简单易懂的ADO.NET及基本语法,这样就清爽多了,:但有个重要的差异是前一个范例可以用JavaScript来按秒传数据,但本范例则必须按下Button按钮才行
参考资料
悉江华《圣殿祭祀的ASP.NET2.0开发祥解-使用C#》电子工业出版社 2006