|
|
最近一段时间在博客园逛的时候,关于Ajax和Atlas的讨论很多很热,看了一些例子和代码,觉得和原来1.1的Postback方式有比较大的区别,而我目前所做的系统的架构和设计都是基于1.1的,如何转移到将来的ASP.NET 2.0,使用无刷新机制来提升客户体验,同时又保留原来的架构和设计,是我最近经常想到的问题。 不久之后,我看到了几位大侠对于ASP.NET 2.0 Callback的描述,称它能够实现轻量级的Ajax,也可以保留Postback方式,这让我豁然开朗,这不就是我想要的吗?如果能够把这种方式移植到1.1中,我们的系统就不用做太大的修改就可以在需要与客户频繁交互的地方采取Callback方式来实现Ajax效果,习惯1.1的程序员也容易了解和转换到Callback方式,并作为将来学习Ajax和Atlas的 铺垫和过渡。以下是大侠的文章 Teddy:深度解析Asp.Net2.0中的Callback机制出走的影子:2.0正式版中callback的一些变化+使用示例(ASP.NET 2.0)How to: Implement Callbacks in ASP.NET Web Pages说干就干,下载.NET 2.0 Framework,随便运行一个页面,将WebResource.axd保存下来,改名为Asp2_Callback.js,客户端Callback所需要的JavaScript脚本就有了。接下来就该Reflector上场了,(真的感谢这个工具让我们能够透过表象看到ASP.NET的内在)。观察一下2.0中的Page对象,果然针对Callback添加了一些方法和属性,找出来加以改写,就成了一个基于1.1的支持Callback的AjaxPage对象了,下面是改写后的代码,帮助您揭开Callback实现之迷。
1 using System; 2 using System.IO; 3 using System.Web; 4 using System.Web.UI; 5 using System.Text; 6 using System.Collections; 7 using System.Collections.Specialized; 8 9 namespace CallbackDemo 10  { 11 /**//// <summary> 12 /// 从System.Web.UI.Page继承,扩展了对Callback的支持 13 /// </summary> 14 public class AjaxPage:System.Web.UI.Page 15 { 16 private bool m_iscallback; 17 private string m_callbackid; 18 private NameValueCollection m_requestValueCollection; 19 private ICallbackEventHandler m_callbackControl; 20 private string m_formid; 21 22 /**//// <summary> 23 /// 判断本次提交是Callback还是Postback 24 /// </summary> 25 public bool IsCallback 26 { 27 get {return m_iscallback;} 28 } 29 30 /**//// <summary> 31 /// 回传的控件ID,此控件的RaiseCallbackEvent和GetCallbackResult方法将被触发 32 /// </summary> 33 public string CallbackID 34 { 35 get {return m_callbackid;} 36 } 37 38 public string FormID 39 { 40 get 41 { 42 if (m_formid==null) 43 m_formid = GetFormID(); 44 return m_formid; 45 } 46 set {m_formid = value;} 47 } 48 49 public AjaxPage() 50 { 51 //如果将页面作为CallbackControl.则需要设置一个默认ID 52 this.ID = "AjaxPage"; 53 m_iscallback = false; 54 m_callbackid = string.Empty; 55 m_requestValueCollection = null; 56 m_formid = null; 57 } 58 59 protected override void OnInit(EventArgs e) 60 { 61 //注册必要的脚本和方法 62 this.RegisterStartupScript("callbackscript","<SCRIPT LANGUAGE=\"javascript\" SRC=\""+this.Request.ApplicationPath+"/asp2_Callback.js\"></SCRIPT>"); 63 this.RegisterStartupScript("mycallback",BuildCallbackCommand()); 64 //根据Post的方式返回Request.QueryString或者Request.Form集合 65 m_requestValueCollection = this.DeterminePostBackMode(); 66 if (this.m_requestValueCollection != null) 67 { 68 //检查回传值确定是否是Callback方式回传 69 m_callbackid = this.m_requestValueCollection["__CALLBACKID"]; 70 if (m_callbackid != null) 71 { 72 m_iscallback = true; 73 } 74 } 75 base.OnInit(e); 76 } 77 78 protected override void OnLoad(EventArgs e) 79 { 80 base.OnLoad(e); 81 if (IsCallback) 82 PrepareCallback(CallbackID); 83 } 84 85 protected override void Render(HtmlTextWriter writer) 86 { 87 if (this.IsCallback) 88 { 89 this.RenderCallback(); 90 } 91 else 92 base.Render(writer); 93 } 94 95 /**//// <summary> 96 /// 根据callbackControlID查找控件,如果该控件实现了ICallbackEventHandler接口就触发RaiseCallbackEvent方法 97 /// </summary> 98 /// <param name="callbackControlID">Callback控件ID</param> 99 private void PrepareCallback(string callbackControlID) 100 { 101 this.Response.Cache.SetNoStore(); 102 try 103 { 104 string callbackparam = this.m_requestValueCollection["__CALLBACKPARAM"]; 105 if (this.ID == callbackControlID) 106 this.m_callbackControl = (ICallbackEventHandler)this; 107 else 108 this.m_callbackControl = this.FindControl(callbackControlID) as ICallbackEventHandler; 109 if (this.m_callbackControl == null) 110 { 111 throw new InvalidOperationException(string.Format("Page_CallBackTargetInvalid, Callback Control ID:{0}", new object[] { callbackControlID })); 112 } 113 this.m_callbackControl.RaiseCallbackEvent(callbackparam); 114 } 115 catch (Exception exception) 116 { 117 this.Response.Clear(); 118 this.Response.Write('e'); 119 if (this.Context.IsCustomErrorEnabled) 120 { 121 this.Response.Write(string.Format("Page_CallBackError")); 122 return; 123 } 124 this.Response.Write(HttpUtility.HtmlEncode(exception.Message)); 125 return; 126 } 127 } 128 129 /**//// <summary> 130 /// 如果是Callback方式则在Render中执行该方法,将m_callbackControl.GetCallbackResult()返回到客户端 131 /// </summary> 132 private void RenderCallback() 133 { 134 string cbsc = this.m_requestValueCollection["__CALLBACKLOADSCRIPT"]; 135 bool flag = !(cbsc==null || cbsc==string.Empty); 136 try 137 { 138 string callbackidx = null; 139 if (flag) 140 { 141 callbackidx = this.m_requestValueCollection["__CALLBACKINDEX"]; 142 if ((callbackidx==null) || (callbackidx==string.Empty)) 143 { 144 throw new HttpException(string.Format("Page_CallBackInvalid")); 145 } 146 for (int idx = 0; idx < callbackidx.Length; idx++) 147 { 148 if (!char.IsDigit(callbackidx, idx)) 149 { 150 throw new HttpException(string.Format("Page_CallBackInvalid")); 151 } 152 } 153 this.Response.Write("<script>parent.__pendingCallbacks["); 154 this.Response.Write(callbackidx); 155 this.Response.Write("].xmlRequest.responseText=\""); 156 } 157 if (this.m_callbackControl != null) 158 { 159 string callbackrlt = this.m_callbackControl.GetCallbackResult(); 160 this.Response.Write('s'); 161 this.Response.Write(callbackrlt); 162 } 163 if (flag) 164 { 165 this.Response.Write("\";parent.__pendingCallbacks["); 166 this.Response.Write(callbackidx); 167 this.Response.Write("].xmlRequest.readyState=4;parent.WebForm_CallbackComplete();</script>"); 168 } 169 } 170 catch (Exception exception1) 171 { 172 this.Response.Clear(); 173 this.Response.Write('e'); 174 if (this.Context.IsCustomErrorEnabled) 175 { 176 this.Response.Write(string.Format("Page_CallBackError")); 177 return; 178 } 179 this.Response.Write(HttpUtility.HtmlEncode(exception1.Message)); 180 } 181 } 182 183 生成Callback方法#region 生成Callback方法 184 public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context) 185 { 186 return GetCallbackEventReference(control,argument,clientCallback,context,null,false); 187 } 188 189 public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context, string clientErrorCallback) 190 { 191 return GetCallbackEventReference(control,argument,clientCallback,context,clientErrorCallback,false); 192 } 193 194 public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync) 195 { 196 if (control == null) 197 { 198 throw new ArgumentNullException("control"); 199 } 200 if (!(control is ICallbackEventHandler)) 201 { 202 throw new InvalidOperationException(string.Format("Page_CallBackTargetInvalid, ID:{0}", new object[] { control.UniqueID })); 203 } 204 return GetCallbackEventReference("'" + control.UniqueID + "'",argument,clientCallback,context,clientErrorCallback,false); 205 } 206 207 public string GetCallbackEventReference(string target, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync) 208![]() |