一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

解析ASP.NET應(yīng)用程序中上傳文件的方案

  在Web程序中上傳文件是很常見的需求。利用HTTP協(xié)議上傳文件的方式非常有限,最常見的莫過于使用<input type="file" />元素進(jìn)行上傳。這種上傳方式會(huì)將內(nèi)容使用multipart/form-data方案進(jìn)行編碼,并將內(nèi)容POST到服務(wù)器端。使用multipart/form-data編碼方式與默認(rèn)的application/x-url-encoded編碼方式相比,在大數(shù)據(jù)量情況下效率要高很多。

  使用<input type="file" />上傳文件最大的優(yōu)勢(shì)在于編程方便,幾乎各種服務(wù)器端技術(shù)都對(duì)這種上傳方式做了良好的封裝,使得程序員能夠直觀地對(duì)客戶端上傳的文件進(jìn)行處理。不過總體來說,這個(gè)協(xié)議并不適合做文件傳輸,解析數(shù)據(jù)流內(nèi)容的代價(jià)相對(duì)較高,并且沒有一些例如斷點(diǎn)續(xù)傳的機(jī)制來輔助,導(dǎo)致在上傳大文件時(shí)經(jīng)常會(huì)力不從心。

  有朋友認(rèn)為使用<input type="file" />上傳文件最大的問題在于內(nèi)存占用太高,由于需要將整個(gè)文件載入內(nèi)存進(jìn)行處理,導(dǎo)致如果用戶上傳文件太大,或者同時(shí)上傳的用戶太多,會(huì)造成服務(wù)器端內(nèi)存耗盡。這個(gè)觀點(diǎn)其實(shí)是錯(cuò)誤的。對(duì)于某些服務(wù)器端的技術(shù),例如Spring Framework,或者早期ASP.NET 1.1時(shí),為了供程序處理,都會(huì)將用戶上傳的內(nèi)容完全載入內(nèi)存,這的確會(huì)帶來問題。但是其實(shí)協(xié)議本身并沒有規(guī)定服務(wù)器端應(yīng)該使用何種方式來處理上傳的文件。例如在現(xiàn)在的ASP.NET 2.0中就已經(jīng)會(huì)在用戶上傳數(shù)據(jù)超過一定數(shù)量之后將其存在硬盤中的臨時(shí)文件中,而這點(diǎn)對(duì)于開發(fā)人員完全透明,也就是說,開發(fā)人員可以像以前一樣進(jìn)行數(shù)據(jù)流的處理。

  ASP.NET 2.0啟用硬盤臨時(shí)文件的閾值(threshold)是可配置的:

<system.web>
  <httpRuntime
    maxRequestLength="Int32"
    requestLengthDiskThreshold="Int32" />
</system.web>

  maxRequestLength自不必說,剛接觸ASP.NET的朋友總會(huì)發(fā)現(xiàn)上傳文件不能超過4M,這就是因?yàn)閙axRequestLength的大小默認(rèn)為4096,這就限制著每個(gè)請(qǐng)求的大小不得超過4096KB。這么做的目的是為了保護(hù)應(yīng)用程序不受惡意請(qǐng)求的危害。當(dāng)請(qǐng)求超過maxRequestLength之后,ASP.NET處理程序?qū)⒉粫?huì)處理該請(qǐng)求。這里和ASP.NET拋出一個(gè)異常是不同的,這就是為什么如果用戶上傳文件太大,看到的并非是ASP.NET應(yīng)用程序中指定的錯(cuò)誤頁(yè)面(或者默認(rèn)的),因?yàn)?a href=/itjie/ASPjishu/ target=_blank class=infotextkey>ASP.NET還沒有對(duì)這個(gè)請(qǐng)求進(jìn)行處理。requestLengthDiskThreshold就是剛才所提到的閾值,其默認(rèn)值為256,即一個(gè)請(qǐng)求內(nèi)容超過256KB時(shí)就會(huì)啟用硬盤作為緩存。這個(gè)閾值理論上和客戶端是否是在上傳內(nèi)容無關(guān),只要客戶端發(fā)來的請(qǐng)求大于這個(gè)值即可。因此,在ASP.NET 2.0中服務(wù)器的內(nèi)存不會(huì)因?yàn)榭蛻舳说漠惓U?qǐng)求而耗盡。

  如果我們需要在ASP.NET(如果沒有特別說明,以下ASP.NET均指ASP.NET 2.0)應(yīng)用中上傳文件,我們一般就會(huì)直接使用<ASP:FileUpload />控件進(jìn)行文件上傳。如果一個(gè)頁(yè)面中存在<ASP:FileUpload />控件,那么頁(yè)面中form元素的enctype就會(huì)被自動(dòng)改為multipart/form-data,而且我們可以在頁(yè)面PostBack之后通過<ASP:FileUpload />控件的引用來獲得客戶端通過該控件所上傳得文件。不過,如果上傳文件的功能需要較為特別的需求——例如需要進(jìn)度條提示,<ASP:FileUpload />控件就無能為力了。

  確切地說,應(yīng)該是<input type="file" />所能提供的支持非常有限,因此一些特殊需求我們不能實(shí)現(xiàn)——嚴(yán)格說來,應(yīng)該是無法輕易地、直接地實(shí)現(xiàn)。這樣,在實(shí)現(xiàn)這些功能時(shí),我們就會(huì)繞一個(gè)大大的彎。為了避免每次實(shí)現(xiàn)相同功能時(shí)都要費(fèi)神費(fèi)時(shí)地走一遍彎路,因此出現(xiàn)了各種上傳組件。上傳組件提供了封裝好的功能,使得我們?cè)趯?shí)現(xiàn)文件上傳功能時(shí)變得輕松了很多。例如幾乎所有的上傳組件都直接或間接地提供了進(jìn)度提示的功能,有的提供了當(dāng)前的百分比數(shù)值,有的則直接提供了一套UI;有的組件只提供了簡(jiǎn)單的UI,有的卻提供了一整套上傳、刪除的管理界面。此外,有的組件還提供了防止客戶端惡意上傳的能力。

  關(guān)于ASP.NET下的上傳組件,最廣為流傳的方式莫過于在ASP.NET Pipeline的BeginRequest事件中截獲當(dāng)前的HttpWorkerRequest對(duì)象,然后直接調(diào)用其ReadEntityBody等方法獲取客戶端傳遞過來的數(shù)據(jù)流,并加以分析和處理。在ASP.NET 1.1時(shí)期,這么做的目的是為了直接將數(shù)據(jù)寫入硬盤,以避免上傳內(nèi)容消耗太多服務(wù)器內(nèi)存,但是現(xiàn)在自然已經(jīng)不會(huì)因?yàn)檫@個(gè)原因而這么做了。從客戶端發(fā)起請(qǐng)求到一定規(guī)模的數(shù)據(jù)傳輸完畢需要一段時(shí)間,那么從HttpWorkerRequest對(duì)象中讀取數(shù)據(jù)流自然需要一段時(shí)間,而在這段時(shí)間內(nèi),客戶端可以使用新的請(qǐng)求進(jìn)行輪詢來獲得當(dāng)前上傳的狀況。這就是獲得上傳進(jìn)度的最傳統(tǒng)的做法。這個(gè)做法的原理很容易理解,但是寫出一個(gè)完整的組件其實(shí)很不容易,尤其是各種細(xì)節(jié)方面的問題會(huì)讓人感到防不勝防。此類組件中最成功且最著名的莫過于NeatUpload了。

  NeatUpload是一個(gè)開源組件,使用LGPL(Lesser General Public License)許可協(xié)議,也就是說它是“business-friendly”的。NeatUpload可以在ASP.NET和mono中使用,能夠?qū)⑸蟼鞯奈募嬖谟脖P中或者Sql Server數(shù)據(jù)庫(kù)中。NeatUpload提供了兩個(gè)服務(wù)器控件:<NeatUpload:InputFile>和<NeatUpload:ProgressBar>。前者用于代替<ASP:FileUpload />,可以通過它訪問到用戶通過特定上傳框上傳的內(nèi)容;后者則是一個(gè)進(jìn)度條顯示控件,負(fù)責(zé)使用彈出窗口或內(nèi)聯(lián)的形式顯示上傳的進(jìn)度。彈出窗口自不必說,而所謂的“內(nèi)聯(lián)”方式其實(shí)只是在頁(yè)面中嵌入一個(gè)Iframe元素,然后通過不斷刷新iframe中的頁(yè)面來進(jìn)行進(jìn)度展示而已——可見它和彈出窗口顯示方式的區(qū)別僅僅在頁(yè)面所處的位置。當(dāng)然,如果我們希望將其移植為AJAX形式也不難,只需開發(fā)一個(gè)頁(yè)面,繼承NeatUpload提供的ProgressPage類,并通過ProgressPage所提供的一些屬性(總字節(jié)數(shù),已上傳字節(jié)數(shù),已花時(shí)間,etc.)來獲得當(dāng)前上傳的進(jìn)度,最后直接使用Response.Write輸出JSON形式的數(shù)據(jù)即可。事實(shí)上原本在iframe(或新窗口)中的頁(yè)面,也是繼承了ProgressPage類,并且使用HTML的方式進(jìn)行呈現(xiàn)而已,本質(zhì)上并沒有太大區(qū)別。

  不過個(gè)人認(rèn)為,其實(shí)NeatUpload的實(shí)用價(jià)值不高(這點(diǎn)稍后再述),它最大的意義還在于提供了一個(gè)完整的優(yōu)秀的示例。NeatUpload設(shè)計(jì)精巧,注釋完整,是個(gè)不可多得學(xué)習(xí)案例。如果能夠?qū)eatUpload的代碼研究一遍,那么相信在編程能力和ASP.NET的理解上都會(huì)上一個(gè)新的臺(tái)階。此外,在NeatUpload站點(diǎn)上還能夠發(fā)現(xiàn)NeatHtml。NeatHtml是一個(gè)開源的Web組件,用于顯示不安全的內(nèi)容(主要是用戶輸入內(nèi)容,例如博客評(píng)論,論壇帖子等等),主要用于避免跨站腳本(XSS,Cross-Site Scripting)等安全問題。作為組件的作者,Dean還將NeatHtml所用到的技術(shù)總結(jié)為一篇Whitepaper,感興趣的朋友可以看一下,這是一份不可多得的技術(shù)資料。

  順便提一下,個(gè)人認(rèn)為目前很多開發(fā)人員的編程能力還不夠,似乎很多人都過早地把精力放在了“設(shè)計(jì)”,或者某個(gè)特定的技術(shù)上,而忽略了最基礎(chǔ)的“編程能力”,也就是將一段思路轉(zhuǎn)化為代碼實(shí)現(xiàn)的能力。我發(fā)現(xiàn),很多朋友在解決問題的時(shí)候,似乎都能很快得到解決方案并且敘述出來,但是真正要使用代碼來表現(xiàn)出來時(shí)卻顯得困難重重。其實(shí)在工作中,思路或解決方案可以通過討論而獲得,但是真正轉(zhuǎn)化為代碼的時(shí)候只能靠自己了。而且編程能力其實(shí)和所謂的“工作經(jīng)驗(yàn)”無關(guān),我建議以“應(yīng)屆畢業(yè)生”“自居”的朋友,可以定心地鍛煉一下自己的編程能力。

  與NeatUpload類似的開源組件還有Memba Velodoc XP Edition,它是Velodoc文件管理系統(tǒng)的核心。不過嚴(yán)格說來,這不僅僅是一個(gè)上傳組件,而是一套文件管理的解決方案,它包含:

  1. 一個(gè)兼容IIS 7集成管道模式的ASP.NET Http Module,支持大文件上傳使用(有趣的是,NeatUpload申明,IIS 7的一個(gè)Bug使它無法在IIS 7集成管道模式中使用)。
  2. 一個(gè)支持?jǐn)帱c(diǎn)續(xù)傳的ASP.NET Http Handler。
  3. 一系列ASP.NET服務(wù)器端控件,提供了文件上傳功能所需的UI,包括一個(gè)多文件上傳控件,一個(gè)ListView控件和一個(gè)進(jìn)度條控件。
  4. 一個(gè)Web應(yīng)用程序,可以替換FTP的交換文件方式,支持Email發(fā)送鏈接。它也是上面所提到的組件的使用示例。
  5. 一個(gè)Windows Service,用于定期清理舊文件。
  6. 一個(gè)測(cè)試項(xiàng)目、一個(gè)部署項(xiàng)目、以及一個(gè)安裝項(xiàng)目。
  7. 文檔。

  回到NeatUpload組件。說實(shí)話,我始終不喜歡這種進(jìn)度獲取方式,因?yàn)槲矣X得通過一個(gè)額外的請(qǐng)求對(duì)服務(wù)器進(jìn)行輪詢無疑是一個(gè)累贅。事實(shí)上,如果需要上傳大文件并且獲得上傳進(jìn)度,目前最好的方式應(yīng)該是使用RIA方式。最典型的RIA上傳方式就是利用Flash了。ActionScript 2.0中已經(jīng)存在FileReference和FileReferenceList組件以支持單文件和多文件的上傳,有了這兩個(gè)組件,上傳的各種信息已經(jīng)能夠完全在客戶端獲得,而上傳進(jìn)度也自然能夠計(jì)算出來。FileReference和FileReferenceList組件非常容易使用,就連像我這樣對(duì)Flash一竅不通的人,也能在短時(shí)間內(nèi)作出一個(gè)簡(jiǎn)單的上傳功能。但是自從有了swfupload,世界就變得更美好了。

  嚴(yán)格說來,通過FileReference所得到的上傳進(jìn)度是“客戶端發(fā)送數(shù)據(jù)的進(jìn)度”,而像NeatUpload的做法得到的是“服務(wù)器端接受數(shù)據(jù)的進(jìn)度”,兩者不可混為一談。

  swfupload也是個(gè)開源組件,顧名思義是使用Flash進(jìn)行上傳。不過對(duì)于swfupload來說,F(xiàn)lash的作用主要是“控制”,而不是“展示”,這無疑給了開發(fā)人員更大的靈活性。swfupload的實(shí)現(xiàn)方式自然是利用了FileReference和FileReferenceList組件所提供的功能,通過Flash與JavaScript的交互能力,使得開發(fā)文件上傳功能變得非常優(yōu)雅和容易。有了swfupload,開發(fā)人員可以使用JavaScript來實(shí)現(xiàn)各種顯示方式,開發(fā)像Flicker一樣酷酷的上傳界面也不再是非常困難的事情了。

  swfupload是個(gè)客戶端組件,它對(duì)于服務(wù)器端來說完全透明,也就是說,服務(wù)器端只需要使用對(duì)待普通form的方式來處理即可。例如在ASP.NET中我們可以使用Generic Handler來處理客戶端的文件上傳。如下,fileCollection變量即為客戶端Post至服務(wù)器端所有文件的集合,我們可以使用name或下標(biāo)的方式來獲得其中的HttpPostedFile對(duì)象。:

public class UploadHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        HttpFileCollection fileColllection = context.Request.Files;
        ...
    }
 
    public bool IsReusable { ... }
}

  既然Flash提供了文件上傳功能,Silverlight作為微軟主推的RIA技術(shù)也不會(huì)缺了這項(xiàng)功能。這篇文章源自Silverlight 2.0的Quick Starts,展示了如何使用Silverlight 2.0開發(fā)文件上傳的功能,感興趣的朋友可以一讀。

  圍繞著ASP.NET中上傳文件這個(gè)話題也討論了不少了,還有什么沒有涉及到的嗎?個(gè)人認(rèn)為其實(shí)至少還有一個(gè)非常重要問題是沒有討論過,那就是在處理上傳文件時(shí)占用ASP.NET處理線程的問題。眾所周知,ASP.NET處理請(qǐng)求時(shí)會(huì)用到線程池中的線程,當(dāng)線程池中的線程被用完之后沒有被處理的請(qǐng)求只能排隊(duì)了。因此增大ASP.NET應(yīng)用程序吞吐量的一個(gè)重要手段,就是為一些耗時(shí)的操作使用異步處理方式(事實(shí)上這一命題可以在大部分應(yīng)用中成立)。例如一個(gè)數(shù)據(jù)庫(kù)查詢操作需要3秒鐘,如果不使用異步操作,處理線程就會(huì)被阻塞,直至查詢完成。如果使用異步方式來執(zhí)行數(shù)據(jù)庫(kù)查詢,在這3秒鐘內(nèi)線程就可以用戶處理其他請(qǐng)求,當(dāng)異步操作結(jié)束之后,ASP.NET就會(huì)使用另一個(gè)線程來繼續(xù)處理這個(gè)請(qǐng)求。

  上傳大文件也是一個(gè)長(zhǎng)時(shí)間占用處理線程的工作,而且遺憾的是,這無法使用異步操作來完成(通過異步操作來釋放處理線程需要操作系統(tǒng)的支持,因此只有少量功能可以使用異步操作)。如果一個(gè)文件上傳需要3分鐘時(shí)間,那么在這3分鐘內(nèi)就會(huì)獨(dú)占一個(gè)處理線程,如果上傳文件的連接一多,就會(huì)大大影響應(yīng)用程序的性能——就像遭受了某種方式的DOS攻擊一樣。因此,即使使用了像NeatUpload和swfupload這樣的組件,也無法解決上傳連接過多造成可用線程減少的問題。要解決這個(gè)問題并不容易,以下是兩種思路(歡迎大家就此問題進(jìn)行討論):

  • 擴(kuò)展IIS,使上傳文件或處理文件的過程不經(jīng)ASP.NET處理,以減少ASP.NET應(yīng)用程序線程的消耗。現(xiàn)在有了IIS 7,如果使用集成管道模式,應(yīng)該也可以使用托管代碼進(jìn)行擴(kuò)展。
  • 使用額外的ASP.NET應(yīng)用程序處理文件上傳,以節(jié)省上傳文件的線程對(duì)原ASP.NET應(yīng)用程序線程的消耗。

  就先說到這里吧。

一個(gè)

NET技術(shù)解析ASP.NET應(yīng)用程序中上傳文件的方案,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 涩涩网址 | 黄网站在线观看视频 | 久久香蕉精品 | 亚洲激情综合网 | 国产1区2区3区在线观看 | 国产特黄一级一片免费 | 999精品免费视频 | 日本亚洲精品色婷婷在线影院 | 国产福利在线观看 极品美女 | 国产高清国内精品福利色噜噜 | 7色影院 | 天天色天天射天天操 | 欧美日韩亚洲精品国产色 | 91香蕉福利一区二区三区 | 久久精品二区 | 伊人免费 | 韩国一级永久免费观看网址 | 久久2017| 1024你懂的国产精品 | 亚洲欧洲视频 | 91在线亚洲 | 亚洲国产成人在人网站天堂 | 亚洲视频四区 | 九九五月天 | 久久久久国产一级毛片高清板 | 男人女人的免费视频网站 | 日韩欧美不卡片 | 日日噜噜噜夜夜爽爽狠狠视频 | 思思久久99热只有精品 | 国产精品网红女主播久久久 | 88av色| 欧美人与物另类 | 五月伊人网| 激情五月激情综合 | 久久亚洲精品国产亚洲老地址 | 337q日本大胆欧美人术艺术 | 一区二区三区亚洲 | 91精品久久久久亚洲国产 | 久久私人影院 | 天天做天天爽爽快快 | 激情 婷婷 |