Posted on 2007-04-04 12:16
Jeffrey Zhao 阅读(7063)
评论(46) 编辑 收藏 所属分类:
Ajax & Atlas相关 、
ASP.NET AJAX
UpdatePanel从一开始就无法支持AJAX的文件上传方式。Eilon Lipton写了一篇文章解释了这个问题的原因。文章中提供了两个绕开此问题的方法:
- 将“上传”按钮设为一个传统的PostBack控件而不是异步PostBack。您可以使用多种方法来这么做:例如将一个按钮放置在UpdatePanel外,将按钮设为某个UpdatePanel的PostBackTrigger,或者调用ScriptManager.RegisterPostBackControl来注册它。
- 建立一个不使用ASP.NET AJAX的上传页面,很多站点已经这么做了。
不过,我们为什么不使UpdatePanel兼容FileUpload控件(<input type="file" />)呢?如果可以这样,一定能够受需要使用UpdatePanel上传文件的用户欢迎。
我们首先要解决的问题是,找到一种能够将信息发送到服务器端的方法。我们都知道XMLHttpRequest只能发送字符串。在这里,我们使用和其他的异步上传文件的解决方案一样,使用iframe来上传文件。iframe元素是一个非常有用的东西,即使在AJAX这个概念出现之前,它已经被用于制作一些异步更新的效果了。
其次,我们应该如何改变当前传输数据的行为呢?幸亏Microsoft AJAX Library有着强大的异步通讯层,我们可以方便创建一个UpdatePanelIFrameExetender来继承Sys.Net.WebRequestExecutor,并且将它交给一个上传文件的WebRequest对象。因此,下面的代码可以作为我们开发组件的第一步:
在上面的代码段中,我们在页面初始化时监听了PageRequestManager对象的beginRequest事件。当PageRequestManager触发了一个异步请求时,我们会检查页面上是否有<input type="file" />控件。如果存在的话,则创建一个新的UpdatePanelIFrameExecutor实例,并分配给即将执行的WebRequest对象。
根据异步通讯层的实现,WebRequest的作用只是一个保存请求信息的容器,至于如何向服务器端发送信息则完全是Executor的事情了。事实上Executor完全可以不理会WebRequest携带的信息自行处理,而我们的UpdatePanelIFrameExecutor就是这样的玩意儿。它会改变页面上的内容,将信息Post到IFrame元素中,并且处理从服务器端获得的数据。(未完待续)
点击这里下载整个项目
English Version
Feedback
fighting~~!!好喜欢老赵与小赵这两个家伙,现在我也要开始Asp.net Ajax 的学习历程:)多谢,收下先
赵老啊,用了你这个新的控件果然解决了那个 "500" 的错误,太感谢你了,这个控件很有用途,多向你学习不会错
@jesh
以前您看到的错误提示是假的,我的控件伪造的,呵呵。
其实是因为解析错误才导致的问题,这次我在解析错误的问题上想的头皮都麻了……总算找到一个兼容各种主流浏览器的方法了。这个问题上IE6和IE7都不同,哎……
哈哈,竟然要先看英文的。。。。。。以后希望中文优先。。
您好,我使用你的这个控件后,上传文件是没问题了,但是我加了判断文件大小的JS后,判断什么的是对的,但是点击保存后,文件是上传了,但是上传完后它报500的错误.再看左下角页面的错误,显示112行注释未结束.我再看页面源码啊,112行完全没问题.麻烦您帮我看看吧.谢谢!
<input id="UploadFile" runat="server" onchange="changeSrc(this)" name="fileUp" type="file" /><asp:Button ID="Button1" runat="server" OnClick="Button1_Click" OnClientClick="return CanUpLoad();" Text="上传"/>
<asp:Label ID="LabImage" runat="server"></asp:Label> <img src="about:blank" id="fileChecker" alt="商品图片" style="display:none;"/>
以下为JS:放在这些控件下面的.
<script type="text/javascript">
var oFileChecker = document.getElementById("fileChecker");
var Upload=false;
function changeSrc(filePicker)
{
oFileChecker.src = filePicker.value;
oFileChecker.style.display="";
}
oFileChecker.onreadystatechange = function ()
{
if (oFileChecker.readyState == "complete")
{
document.getElementById('LabImage').innerText="";
checkSize();
}
}
function checkSize()
{
if (oFileChecker.fileSize > 15360)
{
document.getElementById('LabImage').innerText="文件过大,请重新选择!";
Upload=false;
}
else
{
Upload=true;
}
}
function CanUpLoad()
{
return Upload;
}
</script>
@Fish
能不能给我看一下完整的例子呢?越简单越好,只要能够反映问题。:)
再加个服务器的方法:
protected void Button1_Click(object sender, EventArgs e)
{
if (UploadFile.PostedFile.FileName.Trim() != "")
{
//上传文件
//得到后缀名
string extension = Path.GetExtension(UploadFile.PostedFile.FileName).ToLower();
//验证是图片的方法
if (Common.ValidateUtil.isPicture(extension))
{
//根据时间创建文件名
string fileName = DateTime.Now.ToString("yyyyMMddhhmmss");]
//工程路径+upfile文件夹+加文件名和后缀
string path = Request.PhysicalApplicationPath + "/upfile/" + fileName + extension;
//上传
UploadFile.PostedFile.SaveAs(path);
LabImage.Text = "上传成功!";
//设置上传按钮不可用
Button1.Enabled = false;
}
else
{
LabImage.Text = "只能上传图片!";
}
}
}
下面这就是控件:
<input id="UploadFile" runat="server" onchange="changeSrc(this)" name="fileUp" type="file" /><asp:Button ID="Button1" runat="server" OnClick="Button1_Click" OnClientClick="return CanUpLoad();" Text="上传"/>
<asp:Label ID="LabImage" runat="server"></asp:Label> <img src="about:blank" id="fileChecker" alt="商品图片" style="display:none;"/>
<script type="text/javascript">
var oFileChecker = document.getElementById("fileChecker");
var Upload=false;
function changeSrc(filePicker)
{
oFileChecker.src = filePicker.value;
oFileChecker.style.display="";
}
oFileChecker.onreadystatechange = function ()
{
if (oFileChecker.readyState == "complete")
{
document.getElementById('LabImage').innerText="";
checkSize();
}
}
function checkSize()
{
if (oFileChecker.fileSize > 15360)
{
document.getElementById('LabImage').innerText="文件过大,请重新选择!";
Upload=false;
}
else
{
Upload=true;
}
}
function CanUpLoad()
{
return Upload;
}
</script>
这个就是javascript 方法:
<script type="text/javascript">
var oFileChecker = document.getElementById("fileChecker");
var Upload=false;
function changeSrc(filePicker)
{
oFileChecker.src = filePicker.value;
oFileChecker.style.display="";
}
oFileChecker.onreadystatechange = function ()
{
if (oFileChecker.readyState == "complete")
{
document.getElementById('LabImage').innerText="";
checkSize();
}
}
function checkSize()
{
if (oFileChecker.fileSize > 15360)
{
document.getElementById('LabImage').innerText="文件过大,请重新选择!";
Upload=false;
}
else
{
Upload=true;
}
}
function CanUpLoad()
{
return Upload;
}
</script>
也就这些,错误的意思就是,点击File控件的浏览选取图片,img控件显示图片,再根据fileSize属性得到文件大小,如果不合要求,上传按钮的客户端点击事件返回的就是false,如果图片大小正确,上传按钮就可以点击.
我写的这些功能是实现了,但是图片上传完后它就报500的错误,紧接着看左下角IE错误提示后就提示显示112行注释未结束,当然我页面还有些其他东西,都是些无关紧要的东西.!我看112行也没啥子错误.显示的是其他的控件内容!麻烦您试下吧,谢谢!
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<cc1:ajaxfileuploadhelper id="AjaxFileUploadHelper1" runat="server"></cc1:ajaxfileuploadhelper>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<input id="UploadFile" runat="server" name="fileUp" onchange="changeSrc(this)" style="z-index: 102;
left: 101px; width: 181px; top: 290px" type="file" /><asp:Button ID="Button1" runat="server"
CssClass="Buttons" OnClick="Button1_Click" OnClientClick="return CanUpLoad();"
Style="z-index: 102; left: 101px; top: 290px" Text="上传" /><asp:Label ID="LabImage"
runat="server" ForeColor="Purple"></asp:Label><img id="fileChecker" alt="商品图片" src="about:blank"
style="display: none" />
<script type="text/javascript">
var oFileChecker = document.getElementById("fileChecker");
var Upload=false;
function changeSrc(filePicker)
{
oFileChecker.src = filePicker.value;
oFileChecker.style.display="";
}
oFileChecker.onreadystatechange = function ()
{
if (oFileChecker.readyState == "complete")
{
document.getElementById('LabImage').innerText="";
checkSize();
}
}
function checkSize()
{
if (oFileChecker.fileSize > 15360)
{
document.getElementById('LabImage').innerText="文件过大,请重新选择!";
Upload=false;
}
else
{
Upload=true;
}
}
function CanUpLoad()
{
return Upload;
}
</script>
</ContentTemplate>
</asp:UpdatePanel></div>
</form>
--------------------------------------------------------
protected void Button1_Click(object sender, EventArgs e)
{
if (UploadFile.PostedFile.FileName.Trim() != "")
{
//上传文件
string extension = Path.GetExtension(UploadFile.PostedFile.FileName).ToLower();
string fileName = DateTime.Now.ToString("yyyyMMddhhmmss");
string path = Request.PhysicalApplicationPath + "/upfile/" + fileName + extension;
UploadFile.PostedFile.SaveAs(path);
LabImage.Text = "上传成功!";
LabImage.CssClass = fileName + extension;
Button1.Enabled = false;
}
}
晕,我把这些写在单独的个空页面里,它报sys未定义.又不是报先那个错了.
也许是其他位置有问题?实在看不出来了.哎....
上面那个sys的错误是在在个新建的网站出现的问题..
但是我在我现在的项目里,新建个页面,只加了上面这些控件和方法.
还是先那个错误,上传是成功了,报500的错误,再说43行注释未结束..
我也不知道为什么哦,,麻烦您看看..
昏迷了,后来实验了才知道.您的那控件必须放在UpdatePanel里..
如果只放在ScriptManager下面,保存是保存了,但是会报500的错误.
谢谢您了,解决了ing!
@Fish
不是啊,我的设计是一定要紧贴着ScriptManager放的。您的问题可以给我看一下吗?
@Jeffrey Zhao
请发到jeffz[at]live.com吧。:)
我的问题已经说明白了嘛.就是500的错误.
图片还是上传了.传完后报的错.
我的代码先已经发上来了啦.
比如你可以copy着运行试下,大概就是这样,如果您的没问题.
我再写个简单的错误Demo给您吧!
jeffz[at]live.com
这是什么地址啊?
我晚上传个Demo你吧,现在工作中又遇到一个问题.
使用UpdatePanel后,比如我写了window的load事件执行某一方法.
一开始加载是执行了,点击分页的下一页后它就不执行了,
我现在的解决办法是,setTimeout,不段执行相应的方法.
能有好的解决方法么?.谢谢!...
因为我是调用js的 table 点击表头排序.显示第1页数据时成功调用,没问题,
显示第2页后它就不调用了!...谢谢解答.!
趁中午吃饭时间写了个上传图片的问题例子你了哦。注意查收!
标题:
Fish->图片上传问题例子
:)
@Fish
不能用window.load,用Sys.Application.add_load(...)。
谢谢老赵,有没有Update的技巧专贴啊,我看您的帖子,除了可以用您的控件外,那些代码看都看不懂,主要是sys这对象不熟悉,能否写个全面的Update使用技巧的帖子啊,嘿嘿...或者sys的也行!.谢谢啦.,,这样我也好学习,看您帖子里的代码看得头还是有点晕的.
@Fish
我还是建议看官方文档吧,我的文章都是基于基础使用来的扩展。:)
首先要多谢老赵多次帮助我解决一些问题!
我还想跟老赵同志提一点点意见
可不可以在提供代码的时候多一些注释,尽量让我这个低手能够更好的理解
谢谢啊,这点上我非常欣赏日本的开发方式,严格的要求
好像发错地方了,希望老赵会看到,呵呵
@爱情守望者
好的代码是不用注释就能看懂的,我想我的代码应该做到了这一点吧。
多余的注释反而是bad smell,日本外包这种做法我觉得并不可取。:)
@reddatura
500错误是假的,而是因为返回了客户端无法解析的内容,具体的原因就千奇百怪了。
採用MasterPage,在MasterPage使用ScriptManager,繼承MasterPage後再新的頁面,無論如何都不上傳,這是啥原因噢?
@玄鐵劍
Helper是紧跟着ScriptManager放置的吗?
是挨着放的,出现这个问题怎么解决!parsing near '<script type='text/j'
@崽崽
UpdatePanel里放置了<script></script>元素?我记得已经更新过了……
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<jeffz:AjaxFileUploadHelper ID="AjaxFileUploadHelper1" runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:FileUpload ID="FileUpload1" runat="server" />
为什么要挨着<asp:UpdatePanel ID="UpdatePanel1" runat="server">
这个放,而且吧FileUpload1设置为不显示又会出parsing near '<script type='text/j'这个错,我是想点一个按钮然后再出现那个添加信息的面板,这样怎么做到,学习了,谢谢!!
楼主有没有在firefox测试,我用你这个控件时候,在firefox状态栏一直显示“正在从localhost传送数据”,并且页面的鼠标一直处于运行状态,文件上传是成功的,只是用户体验不是很好,特别是鼠标的运行状态,不知道能不能改善一下!
刚试了下.
页面上放个按钮 点击后 再去点UPDATEPANEL中的 上传 就出现找不到对象了!
怎么解决啊!!!