利用 ICallbackEventHandler接口 实现客户端回调

摘要  现在基于.Net的Ajax框架很多,Ajax已经变得很傻瓜化,甚至MS还很狂的说,现在所有的Asp.Net程序员都可以在简历上写会Ajax技术,MS狂妄的资本就是MS的Asp.Net 2.0 Ajax框架。众多的Ajax框架确实给我们开发带来了很多的方便,甚至把Ajax的应用简化到控件拖拉的地步,但这也直接导致了很多人滥用Ajax,只要高兴就套个UpdatePannel,这已经成为很多程序员的习惯,却不知道这样做得到的往往是反效果,增加了服务器的负担。
  在写程序的过程中,一些小的Ajax效果我不大喜欢去用Ajax框架来做,为了一点点效果就去动用Ajax框架这个相对庞大的家伙显然有点不明智。很多简单的Ajax效果,利用 ICallbackEventHandler接口 ,加点简单的代码就可以很轻松的完成。下面将演示怎样利用ICallbackEventHandler接口 实现客户端回调,实现 检查用户名是可用 的实例。

效果

实现
  既然是利用ICallbackEventHandler接口来实现,那我们先来了解一下ICallbackEventHandler接口。ICallbackEventHandler 接口用于指示控件可以作为服务器的回调事件的目标。任何需要接收回调事件的控件都要实现 ICallbackEventHandler 接口。继承这个接口需要实现两个方法RaiseCallbackEventGetCallbackResult,其中,RaiseCallbackEvent用来处理客户端提交的请求,RaiseCallbackEvente有一个string类型的参数,是客户端提交到服务器端的参数。而GetCallbackResult方法则负责把服务器端的处理结果返回到客户端。
  既然要实现回调功能,客户端当然也少不了要有一个向服务器端发送回调请求的函数。用ClientScriptManager类的GetCallbackEventReference方法可以在页面注册一个回调函数。下面来看看GetCallbackEventReference方法在MSDN中的解释:

语法:
public string GetCallbackEventReference(
Control control,
string argument
string clientCallback
string context
string clientErrorCallback
bool useAsync
)

参数
control
  处理客户端回调的服务器 Control。该控件必须实现 ICallbackEventHandler 接口并提供 RaiseCallbackEvent 方法。

argument   从客户端脚本传递给服务器端的一个参数

clientCallback
  一个客户端事件处理程序的名称,该处理程序接收成功的服务器端事件的结果

context
  启动回调之前在客户端计算的客户端脚本。脚本的结果传回客户端事件处理程序

clientErrorCallback
  客户端事件处理程序的名称,该处理程序在服务器端事件处理程序出现错误时接收结果

useAsync
  true 表示同步执行回调 false 表示异步执行回调

返回值
  调用客户端回调的客户端函数的名称。


了解了上面两点以后,我们就开始来实现这个功能。先要修改页面,继承ICallbackEventHandler接口,以让页面支持回调

public partial class _Default : System.Web.UI.Page ,ICallbackEventHandler

然后我们模拟一个已存在用户的列表,在这里为了简单起见(其实是懒,呵呵),我用了一个string的数组,当然,也可以连接到数据库取得已存在的用户

string[] UserNames = { "LixingTie", "生铁" };

有了已存在用户以后,让我们来实现ICallbackEventHandler接口的成员。首先是实现RaiseCallbackEvent方法处理客户端提交的结果。为了保存RaiseCallbackEvent方法处理的结果,我声明了一个变量CallbackResult来保存。

string CallbackResult = null;
public void RaiseCallbackEvent(string eventArgument)
{
    if(eventArgument == "生铁猪")
        throw new Exception("请别进行人身攻击!");
    CallbackResult = Array.IndexOf(UserNames, eventArgument) != -1 ? "该帐户已注册" : "未注册用户";
}

  这里,在RaiseCallbackEvent方法中,对客户端提交过来的用户名参数eventArgument进行了判断,如果用户名是 "生铁猪" 的话,就抛出一个导常,这主要是用来测试客户端事件处理服务器端处理出错的情况,这里先不理。如果客户端提交上来的用户不是 "生铁猪" ,则判断用户名是否已存在(用户是否在 UserNames 中, 是否为 "LixingTie", "生铁"  之一),如果存在的话,处理结果为 "该帐户已注册" 否则为 "未注册用户"。

继续实现 ICallbackEventHandler接口 的另一个成员 GetCallbackResult 以把处理结果返回到客户端。

    public string GetCallbackResult()
    {
        return CallbackResult;
    }

这个方法的实现就比较简单,就单纯的返回RaiseCallbackEvent方法的处理结果CallbackResult;

实现了 ICallbackEventHandler接口 之后,这时我们需要在客户端注册一个向服务器端发送回调请求的函数,我们在页面的Load事件中实现这一步骤

  protected void Page_Load(object sender, EventArgs e)
    {
        if (Page.Request.Browser.SupportsXmlHttp)
        {
            ClientScriptManager cs = Page.ClientScript;
            string callbackScript = cs.GetCallbackEventReference(this, "GetClientUserName()", "OnCallbackCompleted", null, "OnServerError", true);
            string callbackScriptMethod = "function CallbackScriptMethod() { " + callbackScript + " ;}";
            cs.RegisterClientScriptBlock(this.GetType(), "CallbackScriptMethod", callbackScriptMethod, true);
        }
    }

先用ClientScriptManager cs = Page.ClientScript;来获得页页的ClientScriptManager引用。然后通过GetCallbackEventReference注册发送回调请求的函数,cs.GetCallbackEventReference(this, "GetClientUserName()", "OnCallbackCompleted", "", "OnServerError", true);

  参数一 this 代表处理客户端回调的控件为当前页。

  参数二 "GetClientUserName()" 是页面上的一个javascript函数,该函数返回的是用户在TextBox中输入的用户名,用户名将提交到服务器进行判断,GetClientUserName()函数的具体内容将在下面补上。

  参数三 "OnCallbackCompleted" 表示接收服务器端事件处理结果的javascript函数为 OnCallbackCompleted 函数。

  参数四 null,这个实例不需要用到这个参数,所以给它一个空值。这个参数的具体作用见上面MSDN的解释。

  参数五 "OnServerError",这个参数指定了当服务器端处理出错时,由客户端的javascript函数OnServerError()来接收错误信息并处理。在这个实例中,当用户在TextBox里输入 "生铁猪" 的时候服务器端会抛出错误并调用客户端函数OnServerError()处理错误并显示。

  参数六 true 表示同步执行这次回调。

GetCallbackEventReference函数将根据参数返回一个string类型的发送回调请求的脚本,我们把这个脚本保存在callbackScript变量中。
string callbackScriptMethod = "function CallbackScriptMethod() { " + callbackScript + " ;}"; 这条语句将拼接一个名为CallbackScriptMethod的javascript脚本,然后把回调请求脚本放在这个函数体内。这样做以后就可以在javascript里通过CallbackScriptMethod() 函数引发回调。

cs.RegisterClientScriptBlock(this.GetType(), "CallbackScriptMethod", callbackScriptMethod, true); 这条语句把引发回调的函数CallbackScriptMethod()发送到客户端。

至于if (Page.Request.Browser.SupportsXmlHttp)这句是用来检测客户端浏览器是否XmlHttp,因为回调功能使用了XmlHttp,所以,在不支持XmlHttp的浏览器中,这个功能是不能用的。

至此,服务器端的逻辑就已经完成了。后台完整代码如下


using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page ,ICallbackEventHandler
{
    
string CallbackResult = null;
    
string[] UserNames = "LixingTie""生铁" };

    
protected void Page_Load(object sender, EventArgs e)
    
{
        ClientScriptManager cs 
= Page.ClientScript;
        
if (Page.Request.Browser.SupportsXmlHttp)
        
{
            
string callbackScript = cs.GetCallbackEventReference(this"GetClientUserName()""OnCallbackCompleted"null"OnServerError"true);
            
string callbackScriptMethod = "function CallbackScriptMethod() { " + callbackScript + " ;}";
            cs.RegisterClientScriptBlock(
this.GetType(), "CallbackScriptMethod", callbackScriptMethod, true);
        }

        
else
        
{
            cs.RegisterStartupScript(
this.GetType(), "SupportsXmlHttp""alert('你的浏览器不支持XmlHttp,不能使用回调功能!')",true);
        }

    }


    
public string GetCallbackResult()
    
{
        
return CallbackResult;
    }


    
public void RaiseCallbackEvent(string eventArgument)
    
{
        
if(eventArgument == "生铁猪")
            
throw new Exception("请别进行人身攻击!");
        CallbackResult 
= Array.IndexOf(UserNames, eventArgument) != -1 ? "该帐户已注册" : "未注册用户";
    }

}


现在开始,我们来实现页面的界面和客户端的javascript。页面的内容很简单,就一个用来输入用户名的TextBox,一个发起回调的HTML Button,和一个显示信息的SPAN

<body>
    <form id="form1" runat="server">
        <div>
            <asp:TextBox ID="ClientUserName" runat="server"></asp:TextBox>
            <input id="CheckBtn" type="button" value="检查帐户" onclick="CheckUserName();" />
            <span id="message" style="color:Red;"></span>
        </div>
    </form>
</body>

现在我们来补全刚刚服务器代码中要用到的javascript。代码如下:

    <script language="javascript" type="text/javascript">
        function GetClientUserName()
        {
            return document.getElementById("<%=ClientUserName.ClientID %>").value;
        }
       
        function CheckUserName()
        {
            CallbackScriptMethod();
        }
       
        function OnCallbackCompleted(CallbackResult,context)
        {
            document.getElementById("message").innerText = CallbackResult;
        }
       
        function OnServerError(error)
        {
            alert("错误信息 " + error);
        }
    </script>

GetClientUserName为刚刚服务器端代码需要用到的获取用户输入的用户名的函数。通过document.getElementById("<%=ClientUserName.ClientID %>").value;取得Textbox ClientUserName的值。注意这里用的ID是ClientUserName.ClientID而不是直接用ClientUserName,原因是服务器控件的ID和服务器发送到客户端的ID可能会不同。ClientID是获取发送到客户端的ID。

OnCallbackCompleted 是接收服务器端处理结果的函数。

OnServerError 是处理服务器出错的函数。

CheckUserName 是点击检查按钮时候调用的函数,这个函数将调用服务器端生成的引发回调的函数CallbackScriptMethod(),引发回调。

完整的页面代码如下:

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!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>CallbackTest</title>
    <script language="javascript" type="text/javascript">
        function GetClientUserName()
        {
            return document.getElementById("<%=ClientUserName.ClientID %>").value;
        }
       
        function CheckUserName()
        {
            CallbackScriptMethod();
        }
       
        function OnCallbackCompleted(CallbackResult,context)
        {
            document.getElementById("message").innerText = CallbackResult;
        }
       
        function OnServerError(error)
        {
            alert("错误信息 " + error);
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:TextBox ID="ClientUserName" runat="server"></asp:TextBox>
            <input id="CheckBtn" type="button" value="检查帐户" onclick="CheckUserName();" />
            <span id="message" style="color:Red;"></span>
        </div>
    </form>
</body>
</html>


到这里这个例子就完成了。我们可以在IE中看一下效果。(注:调试客户端错误处理的时候请不要在Debug模式下调试页面,因为在Debug模式下抛出异常的话VS会自动切换到代码中检查代码。右击页面选"在浏览器中查看"就行了。)



可以看到,输入"生铁猪"的时候,除了我们原先定义的错误信息外,后面还符加有一段字符,这段字符具体代表的是什么我不大清楚,我想应该是错误的一些附加信息吧。不知道这样认为对不对,知道的朋友请告诉我一下,谢谢。

总结  感觉上,.Net带给我们的便利还是很多的,我们只需要编写少量代码就可以实现这个回调功能。但是我们在享受.Net带给我们的便利的同时,也千万别忘了这种便利是建立在损耗性能的前题下的。个人认为,在web编程的过程中,如果不是在后台需要访问的元素都尽量用HTML控件去完成,少点用服务器控件。因为服务器控件都是经过封装的,每个控件都有它自己的生命周期,需要经过初始化,加载状态,Render等等步骤最后才输出为我们在客端看到的元素,这必定是要损耗服务器性能的。
  程序之路还在摸索学习之中,如果我有什么错误的地方,请各位大家多多指正,谢谢。

相关  源项目下载:点击这里下载
原文地址:https://www.cnblogs.com/kokoliu/p/916427.html