标题: Asp.net Ajax 1.0 异步回调时,服务器端Render原理(原创)
- Scott.X.Liu 2007-04-25 21:18 阅读:2388
- 评论:11 查看评论 | 添加评论

首先回顾一下
Page页的生命周期

[图片]PreInit
[图片]Init
[图片]InitComplete
[图片]LoadState
[图片]ProcessPostData
[图片]PreLoad
[图片]Load
[图片]LoadComplete
[图片]PreRender       
[图片]PrepareCallback //如果有回调
[图片]PreRenderComplete
[图片]SaveState
[图片]SaveStateComplete
[图片]Render

不论是Asp.net请求,还是Ajax请求,都要执行上面的页生命周期,在Page页最后会调用Page.RenderControl()呈现Page所有子控件流程如下

[图片]Page.RenderControl
[图片]      Control.RenderControl()
[图片]             Control.RenderControl(writer,this.Adapter)
[图片]                   Control.RenderControlInternal()
[图片]                       Control.Render()   //此时Page.Render()将其重写
[图片]                            Control.RenderChildren()
[图片]                                  Control.RenderControlInternal()

 现在关键所在
Control.RenderControlInternal()实现如下
如果不是Asp.net Ajax处理,肯定会执行foreach依次对所有的子控件进行遍历

[图片][图片]Code
[图片] internal void RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
[图片][图片] [图片]{            
[图片]    //正常情况如果不设置RareFields,进行默认的流程依次对所有子控件进行处理,            
[图片]    //如果设置RareFields,意思就是以自定义的方式改写RenderChildren            
[图片]    if ((this.RareFields != null) && (this.RareFields.RenderMethod != null))           
[图片][图片]    [图片]{                
[图片]        writer.BeginRender();          
[图片]        //调用RenderMethod委托,Asp.net Ajax1.0在使用Control.SetRenderMethodDelegate时,对应的回调函数就是在此时处理的                
[图片]        this.RareFields.RenderMethod(writer, this);                
[图片]        writer.EndRender();            
[图片]    }            
[图片]    else if (children != null)            
[图片][图片]    [图片]{                 
[图片]        //如果不设置这个RareFieldsEnsured,会把Page里所有的控件呈现                
[图片]        //依次调用Control里所有子控件的RenderControl                
[图片]        foreach (Control control in children)                
[图片][图片]        [图片]{                    
[图片]           control.RenderControl(writer);                
[图片]        }             
[图片]    }        
[图片]}


以上是Asp.net 的Render处理
肯定有人要问上面的if是干吗的,这个可是微软流的接口呀,整个asp.net ajax全靠这个接口进行处理

在Asp.netAjax1.0上,你肯定要放一个ScriptManager吧
它也是Control的子类,
在Page生命周期的OnPreRender时,它会调用
PageRequestManager.OnPreRender();       

问题就在这,PageRequestManager.OnPreRender()实现如下
_owner.IPage.SetRenderMethodDelegate(RenderPageCallback);

SetRenderMethodDelegate()方法是干什么用的

在Control中,当您调用了SetRenderMethodDelegate会给Control.RareFieldsEnsured设置值  

[图片][图片]Code
[图片]public void SetRenderMethodDelegate(RenderMethod renderMethod)
[图片][图片]        [图片]{
[图片]            //使用OccasionalFields.RareField
[图片]            this.RareFieldsEnsured.RenderMethod = renderMethod;
[图片]            this.Controls.SetCollectionReadOnly("Collection_readonly_Codeblocks");
[图片]        }
[图片]

到这一切就清晰了,当您设置了RenderPageCallback,正常的Asp.net流程就不会再走了,所有的子控件就不会被Render
在Asp.netAjax 1.0中使用

[图片][图片]Code
[图片]private void RenderPageCallback(HtmlTextWriter writer, Control pageControl)
[图片][图片][图片]{           
[图片]     [图片] 
[图片]    //取出当前的HtmlForm
[图片]    IHtmlForm formControl = _owner.IPage.Form;   
[图片]             
[图片]    //手动设置当FormControl.RenderControl时()回调方法  ,因为这个时候Page.Controls里有子控件不会被Render啦,怎么办            
[图片]    //手动处理一个呗              
[图片]    formControl.SetRenderMethodDelegate(RenderFormCallback); 
[图片]            
[图片]    //同样,HtmlForm.RenderControl不会在Page.Controls里自动触发的
[图片]    //这个时候您需要手动的RenderCtronl一下,这样才能调用RenderFormCallback            
[图片]    formControl.RenderControl(formWriter);  
[图片]            
[图片]    //生成客户端回调信息|asyncPostBackControlIDs
[图片]    EncodeString(writer, AsyncPostBackControlIDsToken, String.Empty, GetAsyncPostBackControlIDs(false));            
[图片]    //生成客户端回调信息 |postBackControlIDs
[图片]    EncodeString(writer, PostBackControlIDsToken, String.Empty, GetPostBackControlIDs(false));            
[图片]    //生成客户端回调信息 |updatePanelIDs|tUpdatePanel          
[图片]    EncodeString(writer, UpdatePanelIDsToken, String.Empty, GetAllUpdatePanelIDs());     
[图片]    //生成客户端回调信息 |childUpdatePanelIDs      
[图片]    EncodeString(writer, ChildUpdatePanelIDsToken, String.Empty, GetChildUpdatePanelIDs());            
[图片]    //生成客户端回调信息 |panelsToRefreshIDs
[图片]    EncodeString(writer, UpdatePanelsToRefreshToken, String.Empty, GetRefreshingUpdatePanelIDs());            
[图片]    //生成客户端回调信息 |asyncPostBackTimeout            
[图片]    EncodeString(writer, AsyncPostBackTimeoutToken, String.Empty, _owner.AsyncPostBackTimeout.ToString(CultureInfo.InvariantCulture));      
[图片]}

 

[图片]private void RenderFormCallback(HtmlTextWriter writer, Control containerControl)         
[图片][图片][图片]{          
[图片]    //呈现所有需要回发的的UpdatePanel            
[图片]    if (_updatePanelsToRefresh != null)             
[图片][图片]    [图片]{                
[图片]        foreach (UpdatePanel panel in _updatePanelsToRefresh)                 
[图片][图片]        [图片]{                   
[图片]            if (panel.Visible)                    
[图片][图片]            [图片]{                 
[图片]                panel.RenderControl(_updatePanelWriter);         
[图片]                //    会生成如何的客户端回调信息     
[图片]                //169|updatePanel|UpdatePanel1|\r\n     
[图片]                   <input type=\"submit\" name=\"Button1\" value=\"Button\" id=\"Button1\" />\r\n               
[图片]                 <input name=\"txt\" type=\"text\" value=\"wxy\" id=\"txt\" />\r\n              
[图片]            }                
[图片]         }            
[图片]    }      
[图片]     [图片]                   
[图片]    //依次将页面上所有控件的RenderControl,写入dummyWriter                    
[图片]    foreach (Control control in containerControl.Controls)                     
[图片][图片]    [图片]{                        
[图片]        //将整个Page页上所有的控件写入垃圾器,           
[图片]       //此时,这些控件Render的信息不会发送到客户端
[图片]         control.RenderControl(dummyWriter);          
[图片]    }        
[图片]
[图片]    注意,在RenderFormCallback时,HttpRequest会手动的Flush()将上面的信息刷加IIS
[图片]}
[图片]
[图片]

至于Ctronl.Render时,是如何写入HtmlTextWriter,再写入HttpWriter,
再写回HttpWorkRequest,最终刷回内核,或使用socket发送回服务器,不在本文讨论范围.......

由上可见,Asp.net Ajax,必没有使用传统的HttpRequest.Filter来处理回发信息,而是使用了Asp.net 2.0内置的方式和回调的

Asp.net Ajax回调后呈现到客户端有二个部分,一部分是由RenderFormCallback生成的如下

  RenderFormCallback部分会生成如下的客户端脚本        
 169|updatePanel|UpdatePanel1|\r\n   

[图片]<input type=\"submit\" name=\"Button1\" value=\"Button\" id=\"Button1\" />\r\n               
[图片] <input name=\"txt\" type=\"text\" value=\"wxy\" id=\"txt\" />\r\n   

一部分是RenderPageCallback生成的

[图片] 52|hiddenField
[图片]|__VIEWSTATE|/wEPDwUJNjg1NjA3NDcxZGRCX32AH2I/NEq+gCFrVr49kQDECw==|56
[图片]|hiddenField|__EVENTVALIDATION|/wEWAwKf344xAoznisYGApKGsMIJOfjKisKPYP0O2NXUpNjnA29hMlA=|0
[图片]|asyncPostBackControlIDs|||0|postBackControlIDs|||13|updatePanelIDs||tUpdatePanel1|0
[图片]|childUpdatePanelIDs|||12|panelsToRefreshIDs||UpdatePanel1|2|asyncPostBackTimeout||90|12
[图片]|formAction||Default.aspx|13|pageTitle||Untitled Page|


在客户端的部分Sys.WebForm._onFormSubmitCompleted()会对所有的信息以Json type:type,id:id,content:content进行封装
取出UpdatePanel,设置其innerhtml,客户端详细部分见赵老大的blogs


查看评论 | 添加评论
返回顶部 | 返回首页