![emteeth.gif](https://www.cnblogs.com/CuteSoft_Client/CuteEditor/images/emteeth.gif)
原来我一直使用Ajax pro框架用起来还是比较顺畅的,可是自从Atlas出来了几个CTP版本,我终于有点忍不住了,最可恨的是那几个老外一直在哪里叫嚷,Atlas已经可以用于生产了。咱一想这毕竟是微软的嫡系部队啊,要不用用。谁知到这一用就上了贼船了!且不说现在的asp.net 2 ajax 1.0 beta 已经面目全非了。当然微软的东西一贯是博大精神的,可是bug也不少,尤其麻烦的是,我发现兼容性也有问题。咱不要求和什么Fixfox之类的兼容可是和同样6.0sp1版本的windows98,2000下面的IE那得全兼容吧,可事实确并非如此!
我的程序原来是这样设计的,根据用户权限生成菜单,每个菜单都又一个GUID,用户点击菜单后在客户端调用服务器端的程序,设置参数环境然后返回实际URL,再由客户端导航到该URL。原来用AJAX pro实现很简单没有问题。迁移到Atlas之后,复杂了点儿,使用了Webservice,在客户端的脚本中调用WebService。开发调试的时候没有发现问题,可是到了客户那里就不行了。客户的系统有xp,2000,98,只有xp的系统才行!开始认为是浏览器版本的问题,可是全部升级到IE6+sp1后问题依旧。98下是偶尔可以,2000下面是根本不行,出问题的就是这一行放在页面最后的javascript脚本:
Sys.Application.load.add(doCmd);
看错误信息就是提示对象为空或找不到。我分析好像是Atlas的客户端脚本没有下载或立即执行的语句没有执行。到网上搜了搜,在CSDN上有人提类似的问题,没有人给出解决方案。试着封装了一个函数然后加个延时再调用这一句,依然不行。最后只好放弃了。难道要用回Ajax Pro?肯定不行,Atlas别的方面还不错,而且程序里面不少地方使用了Update Panel,这玩意还是不错的。最后锁定了Callback调用,认真地研究了下,发现这个远没有想象的复杂,比Ajax pro用起来都简单,最简单的就这么几步。
页面级使用callback的方法:
1 ,页面类继承ICallbackEventHandler接口
2 ,实现ICallbackEventH#region ICallbackEventHandler 成员
public string GetCallbackResult()
{
return ExecCommand(cmdID);
}
public void RaiseCallbackEvent(string eventArgument)
{
cmdID = eventArgument;
}
#endregionandler接口
就这么简单,其中cmdID是一个页面类的变量,ExecCommand函数用于从数据库中取得URL
3 ,获取客户端调用脚本,实际上就是由.Net生成对自己生成的WebForm_DoCallback()的函数的调用:
this .ClientScript.GetCallbackEventReference( this , " ' " + cmdId + " ' " , " OnExecResult " , string.Empty, " OnExecError " , true ));
这个函数实际返回的就是一个可以注册到脚本中的字符串,形如,WebForm_DoCallback(' thePage' , 'cmdid', OnExecResult, '', OnExecError, true ); 我所要做得就是把这个加入到我的脚本中:
private void RegisterJs(string cmdid)
{
StringBuilder exec = new StringBuilder();
exec.Append("<script>");
exec.Append("function OnExecResult(result)");
exec.Append("{self.navigate(result);}");
exec.Append("function OnExecError(result)");
exec.Append("{alert('error:'+result);}");
exec.Append("function doCmd(){");
exec.Append(this.ClientScript.GetCallbackEventReference(this, "'" + cmdid + "'", "OnExecResult", string.Empty, "OnExecError", true));
exec.Append("}");
exec.Append("doCmd();");
exec.Append("</script>");
this.ClientScript.RegisterStartupScript(this.GetType(), "exec", exec.ToString());
}
经过测试问题解决了!
1 ,页面类继承ICallbackEventHandler接口
2 ,实现ICallbackEventH#region ICallbackEventHandler 成员
public string GetCallbackResult()
{
return ExecCommand(cmdID);
}
public void RaiseCallbackEvent(string eventArgument)
{
cmdID = eventArgument;
}
#endregionandler接口
就这么简单,其中cmdID是一个页面类的变量,ExecCommand函数用于从数据库中取得URL
3 ,获取客户端调用脚本,实际上就是由.Net生成对自己生成的WebForm_DoCallback()的函数的调用:
this .ClientScript.GetCallbackEventReference( this , " ' " + cmdId + " ' " , " OnExecResult " , string.Empty, " OnExecError " , true ));
这个函数实际返回的就是一个可以注册到脚本中的字符串,形如,WebForm_DoCallback(' thePage' , 'cmdid', OnExecResult, '', OnExecError, true ); 我所要做得就是把这个加入到我的脚本中:
private void RegisterJs(string cmdid)
{
StringBuilder exec = new StringBuilder();
exec.Append("<script>");
exec.Append("function OnExecResult(result)");
exec.Append("{self.navigate(result);}");
exec.Append("function OnExecError(result)");
exec.Append("{alert('error:'+result);}");
exec.Append("function doCmd(){");
exec.Append(this.ClientScript.GetCallbackEventReference(this, "'" + cmdid + "'", "OnExecResult", string.Empty, "OnExecError", true));
exec.Append("}");
exec.Append("doCmd();");
exec.Append("</script>");
this.ClientScript.RegisterStartupScript(this.GetType(), "exec", exec.ToString());
}
当然,使用callback后也有缺点。其一,相当于整个页面做了Postback的工作量,不过对于简单的页面不应有什么性能的问题,我这回调页面就一个HTML控件都没有,用起来那是相当的快!其二,那个貌似先进的Web Service用不到了,有点儿遗憾哈^_^。
看来Callback还是很好用的,以后要多用。另,文中所说的问题没有在asp.net 2 ajax 1.0 beta 中试验,据说这个版本客户端库小了很多,也去掉了好多功能。不过我也不想试了,那位大侠试试,有结果请别忘了在百忙中通知我:)。