随笔 - 58  文章 - 69  评论 - 369 

      回顾上一篇

      我们介绍了如何从HTTP请求流中将数据部分进行截取,同时将数据相关信息进行保存。

      本篇概述:
      用过ajax的朋友应该有听过XmlHttpRequest对象,ajax其实就是通过XmlHttpRequest对象来向服务器发出异步请求,并从服务器获得数据,然后用javascript来操作DOM而更新页面。
      本篇就是要通过XmlHttpRequest对象来实现实时的进度显示。

      效果图:


      正文部分:
      看过有些前辈的做法是通过设置HTTP请求的Refresh头字段来定时刷新页面从而显示进度,但是这样就会带动整个页面一起刷新,就算我们把进度条做成单独的页面,效果仍旧不是太好。我之前试过用ajax的Timer组件,但是不知道是何原因,Timer控件在IIS下预览时总是无法正常发挥作用。苦恼了好一阵子,怀疑是MS的BUG。最后发现了一个很好的替代办法就是利用XmlHttpRequest对象来自己实现定时刷新,这样每次只需向服务器请求很少的数据,减少了对服务器的压力,在后期的测试中,发现这个办法确实很好用,而且在IIS下也一切正常(上图就是IIS下运行的效果)。
      当然如果光有进度条没有数据,那这个进度条也只能是个摆设,所以我把接下来的内容分成两块:进度信息的保存、进度的显示
      
      1、进度信息的保存
      首先我们要明白进度条在这里反应的是什么的进度?毫无疑问是文件上传的进度喽~~在上一篇中,我们对上传的文件数据进行了提取,也就是说这个提取的进度就是我们要显示给客户端的进度。那就简单了,我们只要把已经提取的文件大小与总的文件大小比对一下,就可以知道完成的百分比了。可是问题来了,我们如何知道上传了多少了呢?答案肯定是要用一个变量来保存已经上传的数据量。那这个变量要放在哪里才能让我们既可以在进度页面中访问,又可以在HTTP上传模块中访问呢?
      大家肯定知道一般情况下,用户在多个页面之间访问,会用到Session对象或URL传值来进行页面之前的通信。但是前一篇所介绍的HTTP模块并不属于一个页面,因此我们无法简单的应用Session让进度页面与上传模块实现通信。这里主要还是借鉴高山来客的思路:首先构建一个用于存放文件信息的类,该类主要用来保存文件信息,如:文件名,路径,当前上传的数据量,上传时间等。然后设置一个针对某次上传的唯一ID做为页面中通信的暗号,拥有这个暗号的页面才能获取对应于某次上传的文件信息。现在已经有了两个变量了,接着就要使这两个变量可以被多个页面所使用,方法就是在上传页面中,将这个ID变量注册为该页面的一个隐藏域,这样包含这个页面的HTTP请求流中就会包含那个上传ID。另一个类变量就保存在页面缓存Cache中,并用上传ID做为其编号。
      现在假设已经有了这么一个用于存放文件信息的类UploadFileInfo。
      首先我们要在上传页面的PageLoad中new一个ID,然后注册一个隐藏域用来保存此ID,同时实例化UploadFileInfo类,并将相应的信息写入该类,最后把该类放入Catch:
      

if (!IsPostBack)
{
    UploadFileInfo ufi 
= new UploadFileInfo();
    ufi.strFileGuid 
= Guid.NewGuid().ToString;//用GUID来表示唯一的ID;
    ufi.strTempDir 
= Server.MapPath("TempUpload/" + ufi.strFileGuid + "//");
    ClientScript.RegisterHiddenField(
"UploadID", ufi.strFileGuid);//隐藏域,名字为UploadID,值为ufi.strFileGuid
    HttpContext.Current.Cache.Add(ufi.strFileGuid, ufi, null, DateTime.Now.AddDays(10), TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, null);//加入到Catch中
}


      经过以上步骤,我们就可以在HTTP模块中访问了。
      因为在这次的HTTP请求流中包含了一个隐藏域,所以我们可以对获取的HTTP请求流进行分析,从而获取相应的上传ID,也就是我们之前说的暗号。然后通过Cache的编号找到Cache中的文件信息对象,从而我们可以在后来的数据读取过程中对该对象的上传数据量进行修改。由于是放在Cache中,加之是一个引用对象,所以对该对象修改后,其它代码访问到的都是最新的值。

string sguid = GetUploadId(bPreloadedEnitityBody, eContentEncode);//GetUploadId是自己写的一个方法用来从请求流中获取上传ID
UploadFileInfo ufiFileInfo = (UploadFileInfo)HttpContext.Current.Cache[sguid];//取出文件信息对象


      其它页面如果要使用这个对象就得先获取ID,之后就可以自由操作了。

      2、进度的显示
      从图中我们可以看到,当显示进度的时候,背后的页面成灰色,并且无法响应任何事件,有点类似模态窗口。这个效果大家可以在网上查查,还是挺容易实现的。我这里有一段js显示此效果的代码(搜集于网上):

ModalDialog


      接着讲我们的重点:如何实现定时局部刷新。
      关于XmlHttpRequest对象,我这里就不详细讲述了,提供大家一个关于此的手册下载。为了大家更容易理解,我举个小例子:
  

小例子

   

      通过以上小例子,大家应该已经对该对象有所了解了吧。为实现定时刷新,我把进度条单独放在一个页面中(如A.aspx),通过js的setTimeout来定时执行类似returnresponse这样的方法,然后在A.aspx.cs代码中获取文件信息对象,接着通过Response来反馈进度信息。这样在A.aspx页面中就可以获取到信息,并进行显示了。但是执行ActiveXObject将要花费不少代价,而且我们是定时执行该方法,显然会造成性能下降。在参考了构建一个pool来管理无刷新页面的xmlhttp对象后,决定采用这一方法,事实证明该方法确实有效。

利用pool后的代码

       到这就差不多整个专题都结束了,接下来几天,我会把代码稍微调整下,然后传上来。

       由于这段时间要上班,实在抽不出时间来整理,如果大家需要可以先拿去看看。不过代码写的有点乱,而且有些功能也没有完善,时间实在太少,大家见谅。
       粗糙的工程
posted on 2008-08-04 16:35 stg609 阅读(4256) 评论(43)  编辑 收藏 网摘 所属分类: .Net WebForm开发

  回复  引用  查看    
2008-08-04 16:49 | netcorner      
太复杂,用swfupload简单多了!
  回复  引用  查看    
2008-08-04 17:02 | 足够有晋      
样子很漂亮。
  回复  引用  查看    
2008-08-04 17:07 | stg609      
--引用--------------------------------------------------
netcorner: 太复杂,用swfupload简单多了!
--------------------------------------------------------
恩,本人做这个主要还是为了学习。

  回复  引用  查看    
2008-08-04 17:19 | 莫耶      
SlickUpload早已解决这个问题了
呵呵~

  回复  引用    
2008-08-04 17:38 | xue[未注册用户]
学习!
  回复  引用  查看    
2008-08-04 18:12 | 谦虚的天下      
很好,很强大!
  回复  引用  查看    
2008-08-04 19:50 | 蓝色海岸线      
不错,学习了!
  回复  引用    
2008-08-04 20:31 | bucuo[未注册用户]
不错,学习!
  回复  引用  查看    
2008-08-05 04:12 | 怪怪      
你这个系列很好, 把非swf的方案基本说到位了,过去像你这么完整的, 似乎只有英文文章~

顶一下

  回复  引用    
2008-08-05 08:55 | 1412[未注册用户]
学习了
  回复  引用  查看    
2008-08-05 10:43 | 赖文华(SWPU小赖)      
顶一下!
  回复  引用    
2008-08-05 12:21 | 0574[未注册用户]
好文章,学习
  回复  引用    
2008-08-05 12:49 | 天天他[未注册用户]
发个完整的项目包 试试呢.
  回复  引用  查看    
2008-08-05 16:14 | Martin(高超)      
x效果不错类
  回复  引用  查看    
2008-08-05 17:19 | 隐姓埋名      
LZ `
你的包 还没整理好啊!

  回复  引用  查看    
2008-08-05 22:24 | stg609      
实在抱歉呀,最近没时间整理了,我已经把最原始的工程传上去了,如果大家需要的话,可以去下。
  回复  引用    
2008-08-07 12:06 | scro[未注册用户]
好东西.谢谢楼主
  回复  引用  查看    
2008-08-07 14:09 | 游侠_1      
很鄙视一些人泼冷水,我相信楼主不会自己在项目运用这个东西,但我佩服楼主的钻研精神,做这种东西不再于和别的(如swfupload之类比较),在于对新事务的学习与理解 钦佩这种学习的态度
  回复  引用    
2008-08-07 17:16 | magic_lf[未注册用户]
楼主很强,佩服你的钻研精神
  回复  引用    
2008-08-07 21:19 | TopB[未注册用户]
支持楼主!!!
  回复  引用  查看    
2008-08-18 16:20 | 蔺文龙      
实在是佩服楼主的钻研精神,如今像楼主这样有钻研精神的人,真的不多了!
最近我也在研究这方面的东西

还是希望楼主百忙之中能抽时间,发份比较完整和完善的包供大家学习

  回复  引用  查看    
2008-08-18 16:21 | 蔺文龙      
另外问一下
楼主有没有在较正式的环境里测试过

上传500M~1G左右的文件的效果?

  回复  引用  查看    
2008-08-18 21:39 | stg609      
谢谢支持,不过目前实在是抽不出时间去整理,大家只好先将就下。另外你所指的正式环境是什么?由于条件有限,我目前只在本机测试过,上传过400M多的视频,没有问题。500M以上未曾测试
  回复  引用  查看    
2008-09-02 17:11 | 亦续缘      
怎么没看到你说的效果???
  回复  引用    
2008-09-03 17:26 | 萧萧落幕[未注册用户]
楼主啊,帮帮忙啊,找了好久的东西,被你写的那好,对于我等菜鸟来说好东西啊,

搞了半天硬是没在本机上运行起来,拜托楼主整理下,发到我的邮箱,最好是VS05的工程目录,我刚学,见笑。。。

  回复  引用  查看    
2008-09-04 12:48 | stg609      
谢谢支持,我提供给大家的这个就是完整的VS05的工程文件。不过,实在抱歉,目前还没有精力去整理。
  回复  引用    
2008-09-11 19:26 | weir55[未注册用户]
博主,请教个问题
为什么我运行一直报0001错误啊

  回复  引用    
2008-09-16 09:18 | x-index[未注册用户]
写的很清楚!
  回复  引用  查看    
2008-09-26 11:13 | 时之砂      
怎么有時候上传不成功显示0004,
我debug一开始停止,再上传时debug
上传时提示我不支持support xmlHttp,但是上传成功了!
我的环境:vs2005; net2.0; asp.net ajax;繁体操作系统!

  回复  引用    
2008-11-25 10:34 | liwei783[未注册用户]
楼主,我下了代码运行不了.老是说 if (ufi2.strExtensionName == string.Empty || ufi2.iTotalBytes == 0)
{
Response.Redirect("UploadResult.aspx?Info=error&Code=" + ErrorCodes.Err_0003);
}
对不起,由于网络拥挤或服务器忙,暂时无法上传,请稍后再试 麻烦你发一份好的到我油箱 可以吗 谢谢楼主

  回复  引用    
2008-12-15 15:58 | hoho[未注册用户]
不错啊.楼主是好人,做人很厚道,还把源码提供给大家,好人也!支持你!写的很好!
  回复  引用    
2008-12-15 16:01 | hoho[未注册用户]
对于一些人说自己已经解决了,比什么什么的差,那我觉得你完全没必要过来看!顶楼主!
  回复  引用    
2008-12-15 17:50 | hoho[未注册用户]
楼主,我可以上传,但进度条不动的,百分比也不动的,怎么回事呢?请赐教!
  回复  引用    
2008-12-22 23:26 | amywen[未注册用户]
请问一下楼主,源码在哪下?能否发我邮箱,我找好久了.谢谢了!
  回复  引用  查看    
2009-01-14 14:44 | yinix      
楼主:很好,很强大,顶力支持!!!
  回复  引用    
2009-02-04 22:56 | woradmen[未注册用户]
可以发一份完整的给我吗,谢谢楼主了
  回复  引用    
2009-02-11 17:14 | 一个程序员[未注册用户]
不知道作者有没试过,附带的那个源码,不能上传小的文件,传上去都是空的
  回复  引用    
2009-04-24 13:25 | 感恩[未注册用户]
不错爱益浅,太感谢了,现在也正在做一个要上传大文件的网站
再次谢谢了

  回复  引用    
2009-05-05 18:09 | 很好很强大[未注册用户]
不错 我看过一个例子 没你这个复杂 感觉用滤镜做这个进度条显示不错
  回复  引用    
2009-05-08 08:55 | 谢谢[未注册用户]
整个项目在哪儿啊?
  回复  引用    
2009-05-08 23:25 | 黎族[未注册用户]
楼主,请问.我拿来用时就
var temparray = temp.split(",");
document.getElementById(param[0]).innerText=temparray[0];
报错,说.
Microsoft JScript 运行时错误: 'document.getElementById(...)' 为空或不是对象
怎么回事啊.

  回复  引用    
2009-05-10 01:22 | bleachli
LZ:我用你那个调试一直都有问题.,可不可以发一个你修改了的给我,,发到我邮箱里..谢谢..急啊,,我现在很想学那个东西..
  回复  引用    
2009-06-09 16:36 | luguo[未注册用户]
要是能多写点注释就好了,对于我这种初学者来说!!
发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1259469




相关文章:

相关链接: