随笔-43  评论-206  文章-0  trackbacks-11

神奇的UpdatePanel?

在Microsoft Ajax中,UpdatePanel是一个重要的控件.因为它的存在,我们可以无缝的将Ajax加入到我们的Asp.Net应用程序中.

我们知道,在Asp.Net下Ajax实际上使用了反射,在服务器端动态创建了指定Page的实例并调用实例中的方法,那这就意味着方法的内容无法正常访问当前Page页上控件的内容,但是为什么UpdatePanel中的内容却又可以访问?
UpdatePanel真的很神奇?

OK,现在让我们来揭开UpdatePanel的真实面目.先来看一张图:


上图简要的说明了UpdatePanel中的方法调用的过程,与一般的Ajax的方法调用相比,多了序列化/反序列化及Page实例更新的过程.
这个过程与传统的Asp.Net的执行过程非常相似,对应的为:LoadViewState/SaveViewState.

现在知道了UpdatePanel是如何工作的了,但是还有一个问题:明明是Submit按钮,为什么在UpdatePanel中就无法Submit了呢?
答案是:Form的Submit事件被截获了,也正是因为截获了Submit事件我们才能在客户端序列化我们需要的内容.

以下是实现客户端序列化的部分代码:

  formBody.append(this._scriptManagerID + '=+ this._postBackSettings.panelID + '&');

        
var count = form.elements.length;
        
for (var i = 0; i < count; i++{
            
var element = form.elements[i];
            
var name = element.name;
            
if (typeof(name) === "undefined" || (name === null|| (name.length === 0)) {
                
continue;
            }


            
var tagName = element.tagName;

            
if (tagName === 'INPUT') {
                
var type = element.type;
                
if ((type === 'text') ||
                    (type 
=== 'password') ||
                    (type 
=== 'hidden') ||
                    (((type 
=== 'checkbox') || (type === 'radio')) && element.checked)) {
                    formBody.append(name);
                    formBody.append('
=');
                    formBody.append(encodeURIComponent(element.value));
                    formBody.append('
&');
                }

            }

            
else if (tagName === 'SELECT') {
                
var optionCount = element.options.length;
                
for (var j = 0; j < optionCount; j++{
                    
var option = element.options[j];
                    
if (option.selected) {
                        formBody.append(name);
                        formBody.append('
=');
                        formBody.append(encodeURIComponent(option.value));
                        formBody.append('
&');
                    }

                }

            }

            
else if (tagName === 'TEXTAREA') {
                formBody.append(name);
                formBody.append('
=');
                formBody.append(encodeURIComponent(element.value));
                formBody.append('
&');
            }

        }


        
if (this._additionalInput) {
            formBody.append(
this._additionalInput);
            
this._additionalInput = null;
        }


        
var request = new Sys.Net.WebRequest();
        request.set_url(form.action);
        request.get_headers()['X
-MicrosoftAjax'] = 'Delta=true';
        request.get_headers()['Cache
-Control'] = 'no-cache';
        request.set_timeout(
this._asyncPostBackTimeout);
        request.add_completed(Function.createDelegate(
thisthis._onFormSubmitCompleted));
        request.set_body(formBody.toString());

更多的内容可以查看:MicrosoftAjaxWebForms.js文件.

posted on 2006-12-28 09:10 tablefor2 阅读(2494) 评论(9) 编辑 收藏

评论:
#1楼 2006-12-28 11:16 | Jeffrey Zhao      
兄弟,您完全搞错了

1、UpdatePanel在客户端的确是“截获”了Form的Post,但是没有任何序列化操作,只是使用了JavaScript收集了所有的信息,然后使用XMLHttpRequest模拟了一次普通Post。
2、服务器端也没有任何反序列化操作,也没有使用反射创造Page对象,然后改变其状态。在服务器端接受到的完全也是一个和平时没有多大区别的Post,只是会有一个ScriptManager在观察,发现Request的Header里有'X-MicrosoftAjax'的信息(您贴的代码里就能看到),然后就“截获”ASPX文件的输出,输出的时候也没有任何序列化操作。
3、客户端接受到的信息不是序列化后的内容,而是一种用“|”分割的格式,然后客户端脚本会根据着个信息来更新页面。

经过上面两个步骤,才有了UpdatePanel的效果,当然这只是UpdatePanel工作方式最简单的描述,具体的还会相差很远。
其实您描述的这个过程和客户端访问WebService似乎有些接近,不过没有更新Instance状态的过程,因为Web Service类的实例不用这个步骤。:)

 回复 引用 查看   
#2楼[楼主] 2006-12-28 11:47 | 一醉解千愁      
@Jeffrey Zhao

我所说的客户端序列化跟你说的信息收集是一个道理,我也贴出了收集信息的js脚本,而客户端的反序列化则是一个接受服务器传回来的信息,并更新到UI上的过程.

其实将上面的两个动作理解为序列化和反序列话也没什么问题.

 回复 引用 查看   
#3楼[楼主] 2006-12-28 12:22 | 一醉解千愁      
@Jeffrey Zhao
对于服务器端没有使用放射创造Page对象,以下是
RestHandler类中的一个方法:
private static void InvokeMethod(HttpContext context, WebServiceMethodData methodData, IDictionary<string, object> rawParams)
{
string text1;
RestHandler.InitializeCachePolicy(methodData, context);
object obj1 = null;
if (!methodData.IsStatic)
{
obj1 = Activator.CreateInstance(methodData.Owner.TypeData.Type);
}
object obj2 = methodData.CallMethodFromRawParams(obj1, rawParams);
string text2 = null;
if (methodData.UseXmlResponse)
{
text2 = obj2 as string;
if ((text2 == null) || methodData.XmlSerializeString)
{
try
{
text2 = ServicesUtilities.XmlSerializeObjectToString(obj2);
}
catch (Exception exception1)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.WebService_InvalidXmlReturnType, new object[] { methodData.MethodName, obj2.GetType().FullName, exception1.Message }));
}
}
text1 = "text/xml";
}
else
{
text2 = methodData.Owner.Serializer.Serialize(obj2);
text1 = "application/json";
}
context.Response.ContentType = text1;
if (text2 != null)
{
context.Response.Write(text2);
}
}



 回复 引用 查看   
#4楼 2006-12-28 12:50 | Jeffrey Zhao      
@一醉解千愁
那么就理解为反序列化和序列化吧,不过反射还是没有的。:)

 回复 引用 查看   
#5楼 2006-12-28 12:54 | Jeffrey Zhao      
@一醉解千愁
ASP.NET AJAX的客户端和服务器端的代码我都看过了,所以很熟悉这些实现。
您贴的代码是RestHandler,是用来支持客户端访问Web Service方法的,我也提到了您在文章中的描述和客户端访问Web Service的实现有些接近。而现在的Page Method已经是静态的了。整个ASP.NET AJAX没有用过反射来创建过Page对象。:)
UpdatePanel它只是接受了一个普通的POST,然后由ScriptManager来“劫持”输出的过程。
更多这方面的实现您可以看一下我写的“深入Atlas”系列,虽然它没有根据RC来写,但是很多地方从Beta到RC没有很大的变化。:)

 回复 引用 查看   
#6楼 2006-12-28 13:01 | test[匿名][未注册用户]
看这篇文章,吓了我一跳,作者创造了这么多新名词,
 回复 引用   
#7楼 2006-12-28 13:29 | tttt[未注册用户]
楼上的,这就是所谓的“太空人”创造的名词,
什么AJAX,什么反射,什么序列化,反序列化,浮躁的表现而已

 回复 引用   
#8楼 2006-12-28 13:30 | string[未注册用户]
其实这些东西几天就能熟悉的,很简单的,关键是有没有好的基础。
 回复 引用   
#9楼 2007-02-25 14:52 | 晕[未注册用户]
其实将上面的两个动作理解为序列化和反序列话也没什么问题.

----------
.Net里面这两个词有他们本身的含义,请不要混淆。

 回复 引用   

搜索

 

随笔分类

Links

评论排行榜