Asp.Net 上传大文件专题(4)--利用ajax技术显示上传进度
======================================================
注:本文源代碼點此下載
======================================================
asp.net 上傳大文件專題(4)--利用ajax技術顯示上傳進度
回顧上一篇:
我們介紹了如何從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類,并將相應的信息寫入該類,最后把該類放入cache:
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
function modaldialog(name,divid,width,height,leftop,topop,color)
{
this.name=name;//名稱
this.div=divid;//要放入窗體中的元素名稱
this.width=width;//窗體寬
this.height=height;//窗體高
this.leftop=leftop;//左側位置
this.topop=topop;//上部位置
this.color=color;//整體顏色
this.show=function()//顯示窗體
{
document.all(obj.name+"_divshow").style.width=obj.width;
document.all(obj.name+"_divshow").style.height=obj.height;
document.all(obj.name+"_divshow").style.left=obj.leftop;
document.all(obj.name+"_divshow").style.top=obj.topop;
document.all(obj.name+"_mask").style.width=document.body.clientwidth;
document.all(obj.name+"_mask").style.height=document.body.clientheight;
document.all(obj.name+"_divshow").style.visibility="visible";
document.all(obj.name+"_mask").style.visibility="visible";
}
this.close=function()//關閉窗體
{
document.all(obj.name+"_divshow").style.width=0;
document.all(obj.name+"_divshow").style.height=0;
document.all(obj.name+"_divshow").style.left=0;
document.all(obj.name+"_divshow").style.top=0;
document.all(obj.name+"_mask").style.width=0;
document.all(obj.name+"_mask").style.height=0;
document.all(obj.name+"_divshow").style.visibility="hidden";
document.all(obj.name+"_mask").style.visibility="hidden";
}
this.tostring=function()
{
var tmp="
"+this.name+"_divshow' style='position:absolute; left:0; top:0;z-index:10; visibility:hidden;width:0;height:0'>";
tmp+="";
tmp+="
";
tmp+="
"+this.name+"_content' valign=top >";
tmp+=""
tmp+="";
tmp+="
";
tmp+="
"+this.name+"_mask' style='position:absolute; top:0; left:0; width:0; height:0; background:#666; filter:alpha(opacity=50); z-index:9; visibility:hidden'>
";
document.write(tmp);
document.all(this.name+"_content").insertbefore(document.all(this.div));
}
var obj=this;
}
接著講我們的重點:如何實現定時局部刷新。
關于xmlhttprequest對象,我這里就不詳細講述了,提供大家一個關于此的手冊下載。為了大家更容易理解,我舉個小例子:
小例子
//頁面a.aspx
function returnresponse(url)
{
var xmlhttp = new activexobject('msxml2.xmlhttp');
if(xmlhttp!=null)
{
xmlhttp.open("get",url,true);//向url指定的頁面發送get請求
xmlhttp.onreadystatechange=function()
{//當xmlhttp的readystate改變的時候就會引發這個事件
if(xmlhttp.readystate==4&& xmlhttp.status == 200)
{ //4 = "成功發送",200 = "所請求的頁面返回正常"
temp=xmlhttp.responsetext;//接收所請求頁面發回的數據
alert(temp);
}
}
xmlhttp.send(null);
}
else
{
alert("瀏覽器不支持xmlhttp.");
}
}
//url所指向的頁面b的代碼.cs,當然也可以是同一個頁面的cs
if(request.querystring["event"]=="test")
{
response.write("測試");
}
/**//*
然后我們在a頁中執行returnresponse(b.aspx?event="test");
很快就會發現在a頁中彈出一個窗口,內容是"測試"。
*/
通過以上小例子,大家應該已經對該對象有所了解了吧。為實現定時刷新,我把進度條單獨放在一個頁面中(如a.aspx),通過js的settimeout來定時執行類似returnresponse這樣的方法,然后在a.aspx.cs代碼中獲取文件信息對象,接著通過response來反饋進度信息。這樣在a.aspx頁面中就可以獲取到信息,并進行顯示了。但是執行activexobject將要花費不少代價,而且我們是定時執行該方法,顯然會造成性能下降。在參考了構建一個pool來管理無刷新頁面的xmlhttp對象后,決定采用這一方法,事實證明該方法確實有效。
利用pool后的代碼
function xmlhttppoolfactory()
{
this.xmlhttppool = new array();
this.maxpoollength = 10;
this.add=function()
{
if ( this.xmlhttppool.lengththis.maxpoollength )
{
xmlhttp=null;
if (window.xmlhttprequest)
{// code for all new browsers
xmlhttp=new xmlhttprequest();
}
else if (window.activexobject)
{// code for ie5 and ie6
try
{
xmlhttp = new activexobject('msxml2.xmlhttp');
}
catch(e)
{
try
{
xmlhttp = new activexobject('microsoft.xmlhttp');
}
catch(e2)
{
}
}
}
if ( xmlhttp!=null )
{
this.xmlhttppool.push(xmlhttp);
}
return xmlhttp;
}
};
this.getxmlhttp = function()
{
var xmlhttp = null;
var pool = this.xmlhttppool;
for ( var i=0 ; ipool.length ; ++i )
{
if ( pool[i].readystate == 4 || pool[i].readystate == 0 )
{
xmlhttp = pool[i];
break;
}
}
if ( xmlhttp == null )
{
return this.add();
}
return xmlhttp;
};
this.returnresponse= function(url,div)
{
var xmlhttp = this.getxmlhttp();
var param = div.split(',');
if(xmlhttp!=null)
{
xmlhttp.open("get",url,true);
xmlhttp.onreadystatechange=function()
{
if(xmlhttp.readystate==4&& xmlhttp.status == 200)
{ //4 = "loaded",200 = "ok"
temp=xmlhttp.responsetext;
var temparray = temp.split(",");
document.getelementbyid(param[0]).innertext=temparray[0];
document.getelementbyid(param[1]).innertext=temparray[1]+"kb/s";
document.getelementbyid(param[2]).innerhtml=""+temparray[2]*3+"'>
";
document.getelementbyid(param[3]).innertext=temparray[2]+"%";
}
}
xmlhttp.send(null);
}
else
{
alert("your browser does not support xmlhttp.");
}
};
this.aportall = function()
{
for ( var i=0 ; ithis.xmlhttppool.length ; ++i )
{
this.xmlhttppool[i].abort();
}
};
}
var a = new xmlhttppoolfactory();//建立一個全局的工廠實例
var strevent = "";
function refresh(url,interval,div)
{//該方法我用來定時刷新,因為除了settimeout還有一些其它活要干
var str1 = "";
for(i=2;iarguments.length;i++)
{//因為可能需要刷新的div不只一個,所以利用js的arguments來解決動態參數的問題
if(i!=arguments.length-1)
{
str1 = str1 +arguments[i]+",";
}
else
{
str1 = str1 +arguments[i];
}
}
a.returnresponse(url,str1);//調用該方法實現異部通信
var str="";
for(i=0;iarguments.length;i++)
{
if(i!=arguments.length-1)
str = str + "'"+arguments[i]+"',";
else
str = str+"'"+arguments[i]+"'";
}
settimeout("refresh("+str+")", interval );//定時執行該方法
}
到這就差不多整個專題都結束了,接下來幾天,我會把代碼稍微調整下,然后傳上來。
由于這段時間要上班,實在抽不出時間來整理,如果大家需要可以先拿去看看。不過代碼寫的有點亂,而且有些功能也沒有完善,時間實在太少,大家見諒。
粗糙的工程
綠色通道:好文要頂關注我收藏該文與我聯系
posted on 2008-08-04 16:35 stg609 閱讀(10474) 評論(56)編輯 收藏
發表評論
2241253
回復 引用 查看
#1樓 2008-08-04 16:49 | netcorner
太復雜,用swfupload簡單多了!
回復 引用 查看
#2樓 2008-08-04 17:02 | 足夠有晉
樣子很漂亮。
回復 引用 查看
#3樓[樓主] 2008-08-04 17:07 | stg609
--引用--------------------------------------------------
netcorner: 太復雜,用swfupload簡單多了!
--------------------------------------------------------
恩,本人做這個主要還是為了學習。
回復 引用 查看
#4樓 2008-08-04 17:19 | 莫耶
slickupload早已解決這個問題了
呵呵~
回復 引用
#5樓 2008-08-04 17:38 | xue[未注冊用戶]
學習!
回復 引用 查看
#6樓 2008-08-04 18:12 | 謙虛的天下
很好,很強大!
回復 引用 查看
#7樓 2008-08-04 19:50 | 藍色海岸線
不錯,學習了!
回復 引用
#8樓 2008-08-04 20:31 | bucuo[未注冊用戶]
不錯,學習!
回復 引用 查看
#9樓 2008-08-05 04:12 | 怪怪
你這個系列很好, 把非swf的方案基本說到位了,過去像你這么完整的, 似乎只有英文文章~
頂一下
回復 引用
#10樓 2008-08-05 08:55 | 1412[未注冊用戶]
學習了
回復 引用 查看
#11樓 2008-08-05 10:43 | 賴文華(swpu小賴)
頂一下!
回復 引用
#12樓 2008-08-05 12:21 | 0574[未注冊用戶]
好文章,學習
回復 引用
#13樓 2008-08-05 12:49 | 天天他[未注冊用戶]
發個完整的項目包 試試呢.
回復 引用 查看
#14樓 2008-08-05 16:14 | martin(高超)
x效果不錯類
回復 引用 查看
#15樓 2008-08-05 17:19 | 隱姓埋名
lz `
你的包 還沒整理好啊!
回復 引用 查看
#16樓[樓主] 2008-08-05 22:24 | stg609
實在抱歉呀,最近沒時間整理了,我已經把最原始的工程傳上去了,如果大家需要的話,可以去下。
回復 引用
#17樓 2008-08-07 12:06 | scro[未注冊用戶]
好東西.謝謝樓主
回復 引用 查看
#18樓 2008-08-07 14:09 | 游俠_1
很鄙視一些人潑冷水,我相信樓主不會自己在項目運用這個東西,但我佩服樓主的鉆研精神,做這種東西不再于和別的(如swfupload之類比較),在于對新事務的學習與理解欽佩這種學習的態度
回復 引用
#19樓 2008-08-07 17:16 | magic_lf[未注冊用戶]
樓主很強,佩服你的鉆研精神
回復 引用
#20樓 2008-08-07 21:19 | topb[未注冊用戶]
支持樓主!!!
回復 引用 查看
#21樓 2008-08-18 16:20 | 藺文龍
實在是佩服樓主的鉆研精神,如今像樓主這樣有鉆研精神的人,真的不多了!
最近我也在研究這方面的東西
還是希望樓主百忙之中能抽時間,發份比較完整和完善的包供大家學習
回復 引用 查看
#22樓 2008-08-18 16:21 | 藺文龍
另外問一下
樓主有沒有在較正式的環境里測試過
上傳500m~1g左右的文件的效果?
回復 引用 查看
#23樓[樓主] 2008-08-18 21:39 | stg609
謝謝支持,不過目前實在是抽不出時間去整理,大家只好先將就下。另外你所指的正式環境是什么?由于條件有限,我目前只在本機測試過,上傳過400m多的視頻,沒有問題。500m以上未曾測試
回復 引用 查看
#24樓 2008-09-02 17:11 | 亦續緣
怎么沒看到你說的效果???
回復 引用
#25樓 2008-09-03 17:26 | 蕭蕭落幕[未注冊用戶]
樓主啊,幫幫忙啊,找了好久的東西,被你寫的那好,對于我等菜鳥來說好東西啊,
搞了半天硬是沒在本機上運行起來,拜托樓主整理下,發到我的郵箱,最好是vs05的工程目錄,我剛學,見笑。。。
回復 引用 查看
#26樓[樓主] 2008-09-04 12:48 | stg609
謝謝支持,我提供給大家的這個就是完整的vs05的工程文件。不過,實在抱歉,目前還沒有精力去整理。
回復 引用
#27樓 2008-09-11 19:26 | weir55[未注冊用戶]
博主,請教個問題
為什么我運行一直報0001錯誤啊
回復 引用
#28樓 2008-09-16 09:18 | x-index[未注冊用戶]
寫的很清楚!
回復 引用 查看
#29樓 2008-09-26 11:13 | 時之砂
怎么有時候上傳不成功顯示0004,
我debug一開始停止,再上傳時debug
上傳時提示我不支持support xmlhttp,但是上傳成功了!
我的環境:vs2005; net2.0; asp.net ajax;繁體操作系統!
回復 引用
#30樓 2008-11-25 10:34 | liwei783[未注冊用戶]
樓主,我下了代碼運行不了.老是說 if (ufi2.strextensionname == string.empty || ufi2.itotalbytes == 0)
{
response.redirect("uploadresult.aspx?info=error&code=" + errorcodes.err_0003);
}
對不起,由于網絡擁擠或服務器忙,暫時無法上傳,請稍后再試 麻煩你發一份好的到我油箱 可以嗎 謝謝樓主
回復 引用
#31樓 2008-12-15 15:58 | hoho[未注冊用戶]
不錯啊.樓主是好人,做人很厚道,還把源碼提供給大家,好人也!支持你!寫的很好!
回復 引用
#32樓 2008-12-15 16:01 | hoho[未注冊用戶]
對于一些人說自己已經解決了,比什么什么的差,那我覺得你完全沒必要過來看!頂樓主!
回復 引用
#33樓 2008-12-15 17:50 | hoho[未注冊用戶]
樓主,我可以上傳,但進度條不動的,百分比也不動的,怎么回事呢?請賜教!
回復 引用
#34樓 2008-12-22 23:26 | amywen[未注冊用戶]
請問一下樓主,源碼在哪下?能否發我郵箱,我找好久了.謝謝了!
回復 引用 查看
#35樓 2009-01-14 14:44 | yinix
樓主:很好,很強大,頂力支持!!!
回復 引用
#36樓 2009-02-04 22:56 | woradmen[未注冊用戶]
可以發一份完整的給我嗎,謝謝樓主了
回復 引用
#37樓 2009-02-11 17:14 | 一個程序員[未注冊用戶]
不知道作者有沒試過,附帶的那個源碼,不能上傳小的文件,傳上去都是空的
回復 引用
#38樓 2009-04-24 13:25 | 感恩[未注冊用戶]
不錯愛益淺,太感謝了,現在也正在做一個要上傳大文件的網站
再次謝謝了
回復 引用
#39樓 2009-05-05 18:09 | 很好很強大[未注冊用戶]
不錯 我看過一個例子 沒你這個復雜 感覺用濾鏡做這個進度條顯示不錯
回復 引用
#40樓 2009-05-08 08:55 | 謝謝[未注冊用戶]
整個項目在哪兒啊?
回復 引用
#41樓 2009-05-08 23:25 | 黎族[未注冊用戶]
樓主,請問.我拿來用時就
var temparray = temp.split(",");
document.getelementbyid(param[0]).innertext=temparray[0];
報錯,說.
microsoft jscript 運行時錯誤: 'document.getelementbyid(...)' 為空或不是對象
怎么回事啊.
回復 引用
#42樓 2009-05-10 01:22 | bleachli
lz:我用你那個調試一直都有問題.,可不可以發一個你修改了的給我,,發到我郵箱里..謝謝..急啊,,我現在很想學那個東西..
回復 引用
#43樓 2009-06-09 16:36 | luguo[未注冊用戶]
要是能多寫點注釋就好了,對于我這種初學者來說!!
回復 引用 查看
#44樓 2009-10-09 13:40 | feiyang
請教樓主一個問題,我運行源碼,在ie8下面彈出框沒有,而提示頁面找不到?請問這是什么原因?
回復 引用 查看
#45樓 2009-10-11 15:45 | json-leaf
好帖要留名
回復 引用
#46樓 2009-10-12 17:04 | fdgdf[未注冊用戶]
首先感謝樓主!但有一個小問題,就是我在測試中,上傳文件時進度條沒有數據顯示,我跟蹤代碼發現,在settimeout函數去刷新uploadprogress這個頁面時,調用不到uploadprogress頁面的page_load(),請問這是為什么?
回復 引用 查看
#47樓 2009-11-30 18:34 | joylee
絕對的好文,只知道用別人封裝好的東西,而不去想實現的原理怎么能進步
回復 引用 查看
#48樓 2010-04-29 22:55 | 郭志良
下載下來的源碼 怎么那么多錯誤啊 我是菜鳥,調了老半天 也沒整好, 有更完整的版本嗎? 能發給我嗎?真的很需要。。。
我郵箱:shengxiwgzly@139.com
謝謝了!!!!!
回復 引用 查看
#49樓 2010-05-28 11:19 | plcc
樓主,我下了代碼運行不了.老是說 if (ufi2.strextensionname == string.empty || ufi2.itotalbytes == 0)
{
response.redirect("uploadresult.aspx?info=error&code=" + errorcodes.err_0003);
}
對不起,由于網絡擁擠或服務器忙,暫時無法上傳,請稍后再試 麻煩你發一份好的到我油箱 可以嗎 謝謝樓主
274947209@qq.com
回復 引用 查看
#50樓 2010-07-21 18:02 | 水淼
我用的vs08的怎么轉移過來后直接配置文件就錯了
“/myuploadweb”應用程序中的服務器錯誤。
怎么回事啊,能不能提供個web項目的,不是網站的。
回復 引用 查看
#51樓 2011-01-29 22:41 | 夜之悲哀
對于大文件或者網速慢時,上傳過程瀏覽器的狀態肯定會出現等待進度條,這個怎么去掉?
回復 引用 查看
#52樓 2011-08-14 23:32 | xiawei
樓主呀,現在有整理好的源碼嗎,能給我一份學習用嗎?xiawei_hi@126.com
回復 引用 查看
#53樓 2011-09-01 17:51 | xin_0623
樓主,能傳給我一份源碼嗎?學習一下,謝謝~394663393@qq.com
回復 引用 查看
#54樓 2011-09-19 18:39 | 飛雪連天射白鹿
我也想源碼,,,最近在弄這個東西!
25445828@qq.com
回復 引用 查看
#55樓 2011-09-29 13:52 | xiaosanlun
uploadfileinfo????源碼給一份
回復 引用 查看
#56樓 2011-11-11 15:30 | 木易王子
非常好的東西,樓主,
您的粗糙的工程,我下了個,配置好了,能運行,可傳不上東西,
老師報錯,不知道哪里配錯了,能發份2010的項目源碼給我嗎,
yj1981223@sina.com
注冊用戶登錄后才能發表評論,請 登錄 或 注冊,返回博客園首頁。
首頁博問閃存新聞園子招聘知識庫
最新it新聞:
·android平臺12月廣告瀏覽份額51.6% 超越ios
·測試版ios源代碼顯示ipad 3或將支持siri
·斯蒂芬·霍金的新電腦
·京東商城2.95億競得北京商業地一塊
·美報業巨頭合作facebook谷歌 傳媒重視網絡網絡
? 更多新聞...
最新知識庫文章:
·javascript 面向對象編程
·持續集成之“everything is code”
·持續集成之“軟件自我識別”
·持續集成之戲說check-in dance
·什么是閉包。
? ? ? ?我的理解
? 更多知識庫文章...
china-pub 2011秋季教材巡展
china-pub 計算機絕版圖書按需印刷服務
======================================================
在最后,我邀請大家參加新浪APP,就是新浪免費送大家的一個空間,支持PHP+MySql,免費二級域名,免費域名綁定 這個是我邀請的地址,您通過這個鏈接注冊即為我的好友,并獲贈云豆500個,價值5元哦!短網址是http://t.cn/SXOiLh我創建的小站每天訪客已經達到2000+了,每天掛廣告賺50+元哦,呵呵,飯錢不愁了,\(^o^)/
總結
以上是生活随笔為你收集整理的Asp.Net 上传大文件专题(4)--利用ajax技术显示上传进度的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对c语言课程的总结和认识,c语言课程设计
- 下一篇: 个人求职简历(.Net)--求广州暑期实