现在就要开始整个项目中最有技巧的部分了。如果我们的组件需要在多种浏览器中正常的运行,我们必须好好考虑一下发送和解析数据的方式。如果我们把这部分的机制完全交给ASP.NET AJAX原有的行为来执行,则会遇到问题。下面的代码片断就是IE 7和FireFox在收到服务器端的数据之后,iframe中的DOM结构:

<html><head></head><body><pre>33|updatePanel|ctl00_Main_UpdatePanel1|...</pre></body></html>

很显然,这段代码的意图是为了在页面中直接显示服务器端发送过来的数据。在这种情况下,我们就可以通过“<pre />”元素的innertText属性(IE 7)或者textContent属性(FireFox)来直接获得这段文字。不幸的是,IE6的行为非常奇怪,与前两者可谓大相径庭。IE 6会把这段文字按照XML来解析,接着很自然的显示出错误信息,告诉我们这段文本不是一个有效的XML文档。这非常不合理,因为Response的“Content-Type”是“text/plain”而不是“text/xml”。这是我们要兼容多个浏览器时最头疼的情况。

还记得我们在向客户段输出真实的数据前后都调用了WriteScriptBlock方法吗?下面就是这个方法的实现:

internal static class AjaxFileUploadUtility
{internal static void WriteScriptBlock(HttpResponse response, bool begin){string scriptBegin = "<script type='text/javascript' language='javascript'>window.__f__=function(){/*";string scriptEnd = "*/}</script>";response.Write(begin ? scriptBegin : scriptEnd);}
}

IE 6和IE 7会将使用<script />来包含的文本作为一段脚本代码来处理。我们这里在真实的数据两边加上了脚本定义的内容,使它成为了客户端iframe中“__f__”方法的一段注释,因此我们可以通过调用这个方法的toString函数来获得这个方法的文本内容。请注意在RenderPageCallback方法中,我们把文本进行了编码,将“*/”替换为“*//*”,然后再将其发送到客户端,这么做的目的是使这段文本能够成为合法的JavaScirpt代码。

StringBuilder sb = new StringBuilder();
HtmlTextWriter innerWriter = new HtmlTextWriter(new StringWriter(sb));
renderPageCallbackMethodInfo.Invoke(this.PageRequestManager, new object[] { innerWriter, pageControl });writer.Write(sb.Replace("*/", "*//*").ToString());

等一下,我们在这里把异步刷新运行正常时输出的文本进行了编码,但是我们在异常情况下的输出并没有这么做,不是吗?没错。因为在异常状况下,错误信息会通过Response的Write方法直接输出(请看PageRequestManager类的OnPageError方法),因此我们无法向前面的代码那样获得它输出的结果。我们现在只能希望错误信息中不要出现“*/”这样的字符串吧(当然,我们可以使用反射机制来重写整个逻辑,但是这样做实在比较复杂)。

下面,我们就要在客户端的_iframeLoadComplete方法中重新获取这段文本了:

_iframeLoadComplete : function()
{//...try{    var f = iframe.contentWindow.__f__;var responseData = f ?  : ;if (responseData.indexOf("\r\n") < 0 && responseData.indexOf("\n") > 0){responseData = responseData.replace(/\n/g, "\r\n");}this._responseData = responseData;this._statusCode = 200;this._responseAvailable = true;}catch (e){this._statusCode = 500;this._responseAvailable = false;}// ...
},_parseScriptText : function(scriptText)
{var indexBegin = scriptText.indexOf("/*") + 2;var indexEnd = scriptText.lastIndexOf("*/");var encodedText = scriptText.substring(indexBegin, indexEnd);return encodedText.replace(/\*\/\/\*/g, "*/");
},

我们在这里将判断iframe的window对象中是否存在“__f__”方法,而不是直接判断浏览器的类型来决定下面要做的事情,因为这样可以带来更多的浏览器兼容性。

FireFox的行为则完全不是这样的,它依旧使用我们一开始提到的那种DOM结构,把从服务器端得到的文本显示在iframe中,这种做法比较合理,因为Response的Content-Type为“text-plain”。因此,我们会使用另一种方法来得到这段文本:

_parsePreNode : function(preNode)
{if (preNode.tagName.toUpperCase() !== "PRE") throw new Error();return this._parseScriptText(preNode.textContent || preNode.innerText);
},

请注意,“_iframeLoadComplete”方法中还有几行非常重要的代码:

if (responseData.indexOf("\r\n") < 0 && responseData.indexOf("\n") > 0)
{responseData = responseData.replace(/\n/g, "\r\n");
}

由于从服务器端得到的脚本将会被分割为多个部分,每个部分的格式为“length|type|id|content”,因此字符串的长度是在解析文本时非常重要的属性。因此,我们将会把所有的“\r”替换成“\r\n”,以此保持内容和长度的一致,否则解析过程将会失败。而且事实上,这样的替换只会出现在FireFox中。(未完待续)

点击这里下载整个项目

English Version

让UpdatePanel支持文件上传(4):数据传输与解析机制相关推荐

  1. 让UpdatePanel支持文件上传(2):服务器端组件

    我们现在来关注服务器端的组件.目前的主要问题是,我们如何让页面(事实上是ScriptManager控件)认为它接收到的是一个异步的回送?ScriptManager控件会在HTTP请求的Header中查 ...

  2. 如何使用apiPOST进行模拟发送get、post、delete、put请求(支持文件上传)

    现在的模拟发送请求插件很多,但亲测apiPOST更好用一些,因为它不仅可以模拟发送get.post.delete.put请求,还可以导出文档,中文界面更适合国内的程序员. 今天来分享如何使用apiPO ...

  3. JavaWeb实现文件上传下载功能实例解析

    转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web应用系统开发中,文件上传和下载功能是非常常用的功能 ...

  4. 安卓开发8-WebView支持文件上传

    安卓手机中采用webview访问OA系统,当OA中使用input=file的方式时,点选择文件没有反应,需要在WebChromeClient中增加openFileChooser方法:chrome浏览器 ...

  5. 让nginx支持文件上传的几种模式

    2019独角兽企业重金招聘Python工程师标准>>> 文件上传的几种不同语言和不同方法的总结. 第一种模式 : PHP 语言来处理 这个模式比较简单, 用的人也是最多的, 类似的还 ...

  6. EXTjs 同时支持文件上传和图片上传的htmleditor

    截图: 参照StarHtmleditor的源代码,自己又添加了文件上传功能.源代码如下: Szj_StarHtmleditor.js文件源码: [code] var HTMLEditor = Ext. ...

  7. SpringBoot整合阿里云OSS,支持文件上传、下载、删除、加签等操作

    首先附上OSS基本介绍和官方文档链接:https://help.aliyun.com/product/31815.html?spm=ata.21736010.0.0.25d67536bR4cly 另外 ...

  8. php webwxuploadmedia_PHP Web实现文件上传下载功能实例解析

    PHP用超级全局变量数组$_FILES来记录文件上传相关信息的. 1.file_uploads=on/off 是否允许通过http方式上传文件 2.max_execution_time=30 允许脚本 ...

  9. SpringMVC Web实现文件上传下载功能实例解析

    需求: 项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在20G内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以20G来进行限制. PC端全平台支持,要求支持Window ...

最新文章

  1. C++ 笔记(21)— 处理文件(文件打开、关闭、读取、写入)
  2. 片元着色器(Fragment Shader)被称为像素着色器(Pixel Shader),但
  3. hdu 2154 跳舞毯 (DP)
  4. Hyper-V 网络设置 虚拟机固定Ip
  5. 软件构造学习笔记-第二周
  6. 真正解决办法:FTP 执行命令时500 Illegal PORT command
  7. oracle判断字符串以什么开头_oracle存储过程 判断字符串开头
  8. UEFI shell控制台向.efi文件传入参数--通过protocol实现
  9. K8S中Pod内部容器通信原理
  10. 解决华为手机USB调试app闪退重启界面清空log日志问题
  11. 企业自建私有云-openstack-介绍
  12. 联想y7000桌面没有计算机,【联想拯救者Y7000P笔记本电脑使用体验】屏幕|键盘_摘要频道_什么值得买...
  13. vc读取北通手柄按键_北通手柄驱动按键操作方法详解
  14. 学习笔记(02):3华为工程师 ,带你实战C++(2018版)-02仿函数与智能指针的自实现...
  15. 今日早报 每日精选12条新闻简报 每天一分钟 知晓天下事 2月17日
  16. 微信功能升级:低调开卖全球上网卡 得罪群主进不了群
  17. AOSP中make clean与make clobber的区别
  18. HDOJ 5498 Tree
  19. 分享一些提高逻辑能力的心得
  20. ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilit

热门文章

  1. oracle 查询结果升序,Oracle学习日志-8(查询结果排序)
  2. macbook配置java环境变量_配置mac上Java环境变量
  3. 语音编码 c语言,语音编解码算法G.723.1在DSP - 嵌入式新闻 - 电子发烧友网
  4. linux中的进程权限是,Linux中权限,进程,服务的简单操作
  5. 如何利用扩展欧几里得算法求解不定方程_欧几里德算法、拓展欧几里德、中国剩余定理...
  6. android计算距离顶部的距离,(lua版)计算距离的逻辑是从Android的提供的接口(Location.distanceBetween)中拔来的,应该是最精确的方法了...
  7. 深井软岩巷道群支护技术与应用_深井软岩巷道深浅孔帷幕注浆技术
  8. mysql 查询表的key_mysql查询表和字段的注释
  9. 基于GET报错的sql注入,sqli-lab 1~4
  10. 洛谷P1879 [USACO06NOV]玉米田Corn Fields【状压dp】