小述ASP.NET大文件上传

前段时间有一同事加哥们问我文件上传问题,虽然工作不是很忙,但人一旦松懈下来要想恢复却真的不是很容易,前段时间准备写一个控件开发的专题也半途而废了。这段时间心里有了压力,遂把这个问题研究了下。
做web开发的都知道,在Web程序中上传文件是很常见的需求。利用HTTP协议上传文件的方式非常有限,一般使用<input type="file" />标签来进行上传。这种上传方式会将内容使用
“multipart/form-data”进行编码(multipart/form-data规范原文),并将内容POST到服务器端,然后进行处理。“multipart/form-data”相对于默认的“application/x-url-encoded”,在大数据量提交时效率要高很多。使用<input type="file" />标签上传文件最大的好处在于各种服务器技术都对其最好了封装,开发起来能够很直观的对上传的文件进行处理。不过总体来说,这个协议并不适合做文件传输,解析数据流内容的代价相对较高,并且没有一些例如断点续传的机制来辅助,导致在上传大文件时经常会力不从心。

Web上传文件的原理及实现 

银河使者的这篇文章从java语言介绍了通过<input type="file" />标签把多文件从客户端提交到服务器后进行解析处理,.net版本大致相似。这样就可以自己完成文件上传的操作


ASP.NET的封装

ASP.NET 1.x 提供了一个HtmlInputFile控件,而2.0却出现了一个新的控件FileUpload,但是它生成的html却仍然是一样的,在页面中是用时需要这样来定义:

[ASP.NET 1.x]

<input id="MyFile" type="file" runat="server" />

[ASP.NET 2.0]

<asp:FileUpload id="FileUpload1" runat="server" />

在ASP.NET里文件上传可以说是低效率的代名词,公平的所,IIS却是它的幕后黑手。当你选择一个文件并且按下提交按钮,IIS需要解析文件的所有内容后,你才能读取上传的文件属性,IIS5.X和IIS6都是这样做的,好消息是IIS7.0将会使用Apache的方式。除非你现在就换到7.0,否则你只有长时间等待直到上传完毕,其余一无他法。你也不可以显示进度条因为你压根不知道在这段时间里到底上传了多少。
使用过FileUpload控件的都知道,它真是一把双刃剑——既可能成为我们的救世主(a savior),也能是我们的敌人(an enemy ),其中一个很常见的问题就是如何处理超过4MB的大文
件上传。不过我们应该了解的是,之所以默认的文件大小上限为4MB,并不是因为设计人员想当然,而是为了避免潜在DOS攻击危险。
为了避免这个限制,需要修改配置文件的httpRuntime节的maxRequestLength属性,文件越大,处理的时间也就越长,所以意味着通常你都要修改executionTimeout属性,这个属性1.X默
认是90s,2.0默认是110s,大家可以看下machine.config文件,还有个shutdownTimeout属性,不过我不知道它的用处。

IIS流程

当上传了一个大文件到服务器上,不管你的maxRequestLength设置得多大,IIS都会提取完文件,然后ASP.NET根据system.web/httpRuntime节来判断大小,超过了就会抛出一个异常,这个过程是由HttpRequest的GetEntireRawContent()方法,你可以看到:

部分代码

理论上说可以使文件不是全部加载,但是能配置IIS让它分块读取文件吗?至少我还不知道!

ASP.NET的弊端

ASP.NET处理文件上传的最大的问题在于内存占用太高,由于将整个文件载入内存进行处理,导致如果用户上传文件太大,或者同时上传的用户太多,会造成服务器端内存耗尽。这个观点其实是片面的,对于早期ASP.NET 1.X,为了供程序处理,会将用户上传的内容完全载入内存,这的确会带来问题,但在ASP.NET 2.0中就已经会在用户上传数据超过一定数量之后将其存在硬盘中的临时文件中,而这点对于开发人员完全透明,也就是说,开发人员可以像以前一样进行数据流的处理,这个也在httpRuntime里通过requestLengthDiskThreshold属性来设置阈值(threshold),其默认值为256,即一个请求内容超过256KB时就会启用硬盘作为缓存,这个阈值和客户端是否是在上传内容无关,只关心客户端发来的请求大于这个值。因此,在ASP.NET 2.0中服务器的内存不会因为客户端的异常请求而耗尽。
另外一个弊端就是当请求超过maxRequestLength(默认4M)之后,ASP.NET处理程序将不会处理该请求。这和ASP.NET抛出一个异常完全不同,这就是为什么如果用户上传文件太大,看到的并不是ASP.NET应用程序中指定的错误页面(或者默认的),因为ASP.NET还没有对这个请求进行处理。还有一个问题就是处理超时。这个其实可以通过在运行时读取web.config中的httpRuntime节,并转化为HttpRuntimeSection对象或者重写Page.OnError()来检测HTTP Code(相应代码)是否为400来处理,这里不再赘述,代码如下:

运行时代码

 

OnError代码

对于文件上传的功能需要较为特别的需求——例如进度条提示,ASP.NET封装的控件<asp:FileUpload />就无能为力了。  

好的解决方案

Robert Bazinet建议,最好的解决方案是使用RIA,大多数情况下,建议用Silverlight或Flash的上传组件来替代传统的FileUpload组件,这类组件不只是提供了更好的上传体验,也比<input type="file">标签在页面上的文本框、按钮漂亮,这个<input type="file">标签并不能够通过CSS添加样式,不过也有人尝试去解决了。至今为止并没有什么商业上传组件使用了Silverlight,不过这里有演示了用Silverlight进行多文件上传的示例程序
当然使用Silverlight就可以很轻松的实现多线程上传,断点续传这种功能了,
这些都不是我要详细讨论的内容,如果有需要可以自己去看下。

可选择的解决方案

使用<input type="file" />标签所能提供的支持非常有限,一些特殊需求我们不能实现——或者说是无法轻易地、直接地实现。所以为了实现这样的功能我们每次都要绕一个大大的弯。为了避免每次实现相同功能时都要费神费时地走一遍弯路,市面上或者开源界出现了各种上传组件,上传组件提供了封装好的功能,使得我们在实现文件上传功能时变得轻松了很多。例如几乎所有的上传组件都直接或间接地提供了进度提示的功能,有的提供了当前的百分比数值,有的则直接提供了一套UI;有的组件只提供了简单的UI,有的却提供了一整套上传、删除的管理界面。此外,有的组件还提供了防止客户端恶意上传的能力。
我觉得最好的办法是在HttpModule里分块读取文件并且保持页面激活的状态,这样就不会超时,同时也可以跟踪进度或者取消上传,或者通过HttpHandler实现,在通过进度条给用户充分提示的同时,也
让开发人员能够更好地控制文件大小以及上传过程中可能出现的异常。上传组件都是用这些办法的,我们的选择有:

上传组件

NeatUpload是在ASP.NET Pipeline的BeginRequest事件中截获当前的HttpWorkerRequest对象,然后直接调用其ReadEntityBody等方法获取客户端传递过来的数据流,并加以分析和处理。并通过使用新的请求进行轮询来获取当前上传的状态。关于NeatUpload和其他开源组件的介绍可以参看JeffreyZhao在ASP.NET应用程序中上传文件,当然他还说了Memba Velodoc XP Editionswfupload,写的非常棒!

HttpWorkerRequest实现介绍

利用隐含的HttpWorkerRequest,用它的GetPreloadedEntityBody和ReadEntityBody方法从IIS为ASP.NET建立的pipe里分块读取数据可以实现文件上传。实现方法如下:

HttpWorkerRequest代码

结论

ASP.NET的文件上传是一个不完善和有缺陷的领域,相信在不久会得到提高和发展,如果你已经解决了,说明你在一个好公司,否则你可以考虑使用第三方产品来解决了。文件上传的问题,我们都能够找到很多种不同的方法来解决,挑战在于找出不同做法的利弊然后找到一个适用于自己项目的方案,这不仅仅是在文件上传这一个方面!

参考资料:
1.随便说说:在ASP.NET应用程序中上传文件
2.Handling Large File Uploads in ASP.NET
3.Uploading Files in ASP.NET 2.0
4.The Dark Side of File Uploads
5.ASP.NET Custom Error Pages

PS:写一篇博客太麻烦了,发布了n次!

posted @ 2008-07-08 17:04 wit 阅读(3619) 评论(13)  编辑 收藏 网摘 所属分类: asp.net(2.0)

  回复  引用  查看    
#1楼 2008-07-08 17:36 | 萧寒      
不错!受益不少
  回复  引用  查看    
#2楼 [楼主]2008-07-08 17:40 | wit      
@萧寒
谢谢!
  回复  引用  查看    
#3楼 2008-07-08 18:52 | BAsil      
顶一下
  回复  引用    
#4楼 2008-07-08 19:38 | jason_song [未注册用户]
我曾经用C#做过一个上传组件。我的方法是在服务器端添加一个WebService,然后使用WSE 3.0提供的MTOM机制实现二进制数据传输,还顺便实现了断点续传。效果还不错。
  回复  引用  查看    
#5楼 2008-07-08 20:52 | Anders Liu      
e...貌似没有说什么……
  回复  引用    
#6楼 2008-07-09 02:18 | dv [未注册用户]
  回复  引用    
#7楼 2008-07-09 09:11 | leleele [未注册用户]
不错~系统的总结了下~digg下
  回复  引用  查看    
#8楼 2008-07-09 10:35 | 风海迷沙      
如果不是正规需要的话我用这个组件解决一些小问题,带进度条的
http://krystalware.com/Products/SlickUpload/Demos.aspx
  回复  引用    
#9楼 2008-08-20 10:12 | 俺姓李 [未注册用户]
小弟不才,看了几天都搞不出来,兄弟能否将2.0的code也给我一份啊。

在此先拜谢了。

asong@softstb.com;
71181397
  回复  引用    
#10楼 2008-08-25 15:28 | hjg515 [未注册用户]
建议你使用酷达免费软件,这种软件专门用来传输大文件的,我用了,速度非常快!在http://www.qoodaa.com.cn可以下载到
  回复  引用    
#11楼 2008-08-25 15:38 | hjg515 [未注册用户]
大文件传送,大照片发送,跨国文件传送,网络传输加速,跨国网络传输
Qoodaa传输精灵拥有1G以上大容量文件跨国传输功能,多种文件格式供您选择,高速便捷;且十分易于操作。让您的海外客户或同事第一时间获取你的信息。无论多大容量,现在都可以轻松传输啦!除了用Qoodaa与同事进行即时或离线文件传输外,闲暇时,您还可以用Qoodaa下载英文电影,工作娱乐两不误!
想以最快速度传输大容量文件给您海外的同事吗?现在不必为此烦恼了,只要轻松点击Qoodaa里面的上传和下载,就可以建立一个国际之间“传输专线”了。赶快试试吧!有了Qoodaa为您提供的这些服务,您就可以轻松方便地与同事朋友分享资源。这些服务都是免费的,而且简单易用。如果您还不了解,不妨今天就试试吧!了解更多,详情请登陆http://www.qoodaa.com.cn





  回复  引用    
#12楼 2008-09-19 14:53 | 路人甲66666 [未注册用户]
--引用--------------------------------------------------
jason_song: 我曾经用C#做过一个上传组件。我的方法是在服务器端添加一个WebService,然后使用WSE 3.0提供的MTOM机制实现二进制数据传输,还顺便实现了断点续传。效果还不错。
--------------------------------------------------------


我也是这么干的,很不错,不过MTOM的代码大家要好好改改,主要是验证身份那一块大家要注意
  回复  引用    
#13楼 2008-10-07 17:43 | hjg515 [未注册用户]
大文件传送,大照片发送,跨国文件传送,跨国文件传输,网络传输加速,跨国网络传输,都是酷达的代名词。
酷达软件科技有限公司,长期以来致力于互联网数据传输加速的研究,在互联网数据传输加速方面处于全球领先地位。公司已经为众多的跨国企业提供大数据传输服务。公司拥有一批硅谷归来的研发精英,在网络传输加速方面积累了大量的技术创新;2007年10月,公司研发团队重拳出击,在Qoodaa0.08中加入了自主创新的MNP2P技术,在跨国传输方面取得了革命性的进展,把竞争对手远远地抛到了身后。拥有酷达传输,信息畅游天下。酷达流畅的界面,简单的操作,清新的风格,超越极限的传输速度,最终奠定了酷达在互联网大文件传输行业的霸主地位。公司在前进的过程中经历了许多的坎坷和荆棘,但是,广大用户对我们的支持和肯定最终让我们克服了艰难险阻,Qoodaa0.08产品得到了广大用户的一致好评。我们的研发团队将一如既往,从稳定性、安全性,传输效率等多方面进行改进,帮助更多的企业和个人把信息传输到世界各地。网址:http://www.qoodaa.com.cn


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-07-10 16:07 编辑过
Google站内搜索


China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
近千种 9-95 新二手计算图书火热销售中!

相关文章:


相关搜索:
asp.net 2.0 file upload

相关链接: