最近在做一个项目,需要在UpdatePanel中上载文件,在网络上找了一下,发现有老赵写的AjaxUploadHelper,一开始工作的很好;开发时使用localhost来进行测试的,一切正常;但部署到正式环境后,噩梦开始了,所有在UpdatePanel内的异步操作都不正常,都提示如下信息:
Sys.WebForms.PageRequestManagerServerErrorException: An unknown error occurred while processing the request on the server. The status code returned from the server was: 500
一开始以为是开发环境与正式环境不同导致服务器端输出HTTP 500的错误呢,但怎么也找不到服务器上有关异常的日志信息,后来偶然把上载文件的控件设置为Visible = false,竟然不报这个错了,一切正常;研究了一下AjaxUploadHelper这个控件,是使用iframe来提交的,而不幸的是我们的系统需要跟别的老系统进行页面上的交互,所以系统的BasePage统一输出了一段脚本来设置document.domain,以让2个子域的系统进行交互:
2 document.domain = 'devfx.net';
3} catch(e) {;}
但是,AJAX异步通过iframe提交,输出的结果是不会有这段脚本的,这导致主页面的document.domain = 'devfx.net',而iframe却是真正域local.devfx.net,所以AjaxUploadHelper内的脚本获取不了iframe的内容,浏览器报Access Denied,AjaxUploadHelper的脚本把这个错误统一封装成500的错误了,可以看一下AjaxFileUploadHelper.js的代码:
{
var f = iframe.contentWindow.__f__;
var responseData = f ? this._parseScriptText(f.toString()) :
this._parsePreNode(iframe.contentWindow.document.body.firstChild);
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;
}
i,害人哪。。。。
既然知道了是由于跨域产生的,解决起来就比较容易了。
修改AjaxUploadHelper,增加属性ClientDocumentDomain,用以设置iframe的document.domain:
{
AjaxFileUploadUtility.WriteScriptBlock(this.Page.Response, true);
StringBuilder sb = new StringBuilder();
HtmlTextWriter innerWriter = new HtmlTextWriter(new StringWriter(sb));
renderPageCallbackMethodInfo.Invoke(this.PageRequestManager, new object[] { innerWriter, pageControl });
writer.Write(sb.Replace("*/", "*//*").ToString());
AjaxFileUploadUtility.WriteScriptBlock(this.Page.Response, false);
if(!string.IsNullOrEmpty(this.ClientDocumentDomain)) {
string domainScript = string.Format("<script type='text/javascript' language='javascript'>try {{ document.domain = '{0}'; }} catch(e) {{;}}</script>", this.ClientDocumentDomain);
writer.Write(domainScript);
}
}
上面的修改只是针对AjaxUploadHelper而改的。修改后的代码包:New AjaxFileUploadHelper。
到目前为止,老赵又发了更新:让UpdatePanel支持上传文件,这次使用了jquery以及插件jquery.form.js,把原来自己创建iframe的工作交由给jquery.form来处理,而且针对的framework是3.5的,(老赵发的代码包缺了好多脚本,害我好找!!);我以为新版本能把这个问题解决,可惜还是没有;我以为按修改AjaxUploadHelper方法就可以了,尝试了3天到目前为止还没有很完美的解决方案。主要的障碍在AJAX异步回调后,输出的是Content-Type是text/plain,如果这个时候输出脚本来设置domain,似乎任何脚本都不会被执行(好像浏览器把输出仅当成文本了),自然iframe的document.domain还是不对的,所以还是会报500的假错误(貌似AjaxUploadHelper控件却是可以的,不解了);如果完全改成AjaxUploadHelper的操作方式,不知道会不会解决;等有空的时候在深入研究研究。