自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

ASP.NET大文件上傳詳解

開發(fā) 后端
本文向您介紹ASP.NET大文件上傳,通過Web上傳文件的原理及實現、ASP.NET的封裝至IIS流程主要講速HttpWorkerRequest性能。

做web開發(fā)的都知道,在Web程序中上傳文件是很常見的需求。

利用HTTP協議上傳文件的方式非常有限,一般使用〈input type="file" / 〉標簽來進行上傳。

這種上傳方式會將內容使用“multipart/form-data”進行編碼(multipart/form-data規(guī)范原文),并將內容POST到服務器端,然后進行處理。“multipart/form-data”相對于默認的“application/x-url-encoded”,在大數據量提交時效率要高很多。使用〈input type="file" /〉標簽上傳文件最大的好處在于各種服務器技術都對其最好了封裝,開發(fā)起來能夠很直觀的對上傳的文件進行處理。不過總體來說,這個協議并不適合做文件傳輸,解析數據流內容的代價相對較高,并且沒有一些例如斷點續(xù)傳的機制來輔助,導致在上傳大文件時經常會力不從心。

Web上傳文件的原理及實現

銀河使者的這篇文章從java語言介紹了通過〈input type="file" /〉標簽把多文件從客戶端提交到服務器后進行解析處理,.net版本大致相似。這樣就可以自己完成文件上傳的操作。

ASP.NET的封裝

ASP.NET 1.x 提供了一個HtmlInputFile控件,而2.0卻出現了一個新的控件FileUpload,但是它生成的html卻仍然是一樣的,在頁面中是用時需要這樣來定義:

[ASP.NET 1.x]

  1. 〈input id="MyFile" type="file" runat="server" /〉  

[ASP.NET 2.0]

  1. "FileUpload1" runat="server" />  

ASP.NET大文件上傳可以說是低效率的代名詞,公平的所,IIS卻是它的幕后黑手。當你選擇一個文件并且按下提交按鈕,IIS需要解析文件的所有內容后,你才能讀取上傳的文件屬性,IIS5.X和IIS6都是這樣做的,好消息是IIS7.0將會使用Apache的方式。除非你現在就換到7.0,否則你只有長時間等待直到上傳完畢,其余一無他法。你也不可以顯示進度條因為你壓根不知道在這段時間里到底上傳了多少。

使用過FileUpload控件的都知道,它真是一把雙刃劍——既可能成為我們的救世主(a savior),也能是我們的敵人(an enemy ),其中一個很常見的問題就是如何處理超過4MB的大文件上傳。不過我們應該了解的是,之所以默認的文件大小上限為4MB,并不是因為設計人員想當然,而是為了避免潛在DOS攻擊危險。

為了避免這個限制,需要修改配置文件的httpRuntime節(jié)的maxRequestLength屬性,文件越大,處理的時間也就越長,所以意味著通常你都要修改executionTimeout屬性,這個屬性1.X默認是90s,2.0默認是110s,大家可以看下machine.config文件,還有個shutdownTimeout屬性,不過我不知道它的用處。

IIS流程

當ASP.NET大文件上傳到服務器上,不管你的maxRequestLength設置得多大,IIS都會提取完文件,然后ASP.NET根據system.web/httpRuntime節(jié)來判斷大小,超過了就會拋出一個異常,這個過程是由HttpRequest的GetEntireRawContent()方法,你可以看到:

  1.  HttpRuntimeSection httpRuntime = RuntimeConfig.  
  2. GetConfig(this._context).HttpRuntime;  
  3. int maxRequestLengthBytes = httpRuntime.  
  4. MaxRequestLengthBytes;  
  5. if (this.ContentLength  〉maxRequestLengthBytes)  
  6. {  
  7. if (!(this._wr is IIS7WorkerRequest))  
  8. {  
  9. this.Response.CloseConnectionAfterError();  
  10. }  
  11. throw new HttpException(SR.GetString  
  12. ("Max_request_length_exceeded"), null, 0xbbc);  
  13. }  

理論上說可以使文件不是全部加載,但是能配置IIS讓它分塊讀取文件嗎?至少我還不知道!

ASP.NET的弊端

ASP.NET處理文件上傳的最大的問題在于內存占用太高,由于將整個文件載入內存進行處理,導致如果用戶上傳文件太大,或者同時上傳的用戶太多,會造成服務器端內存耗盡。這個觀點其實是片面的,對于早期ASP.NET 1.X,為了供程序處理,會將用戶上傳的內容完全載入內存,這的確會帶來問題,

但在ASP.NET 2.0中就已經會在用戶上傳數據超過一定數量之后將其存在硬盤中的臨時文件中,而這點對于開發(fā)人員完全透明,也就是說,開發(fā)人員可以像以前一樣進行數據流的處理,

這個也在httpRuntime里通過requestLengthDiskThreshold屬性來設置閾值(threshold),其默認值為256,即一個請求內容超過256KB時就會啟用硬盤作為緩存,這個閾值和客戶端是否是在上傳內容無關,只關心客戶端發(fā)來的請求大于這個值。

因此,在ASP.NET 2.0中服務器的內存不會因為客戶端的異常請求而耗盡。

另外一個弊端就是當請求超過maxRequestLength(默認4M)之后,ASP.NET處理程序將不會處理該請求。這和ASP.NET拋出一個異常完全不同,這就是為什么如果用戶上傳文件太大,看到的并不是ASP.NET應用程序中指定的錯誤頁面(或者默認的),因為ASP.NET還沒有對這個請求進行處理。

還有一個問題就是處理ASP.NET大文件上傳的超時。

這個其實可以通過在運行時讀取web.config中的httpRuntime節(jié),并轉化為HttpRuntimeSection對象或者重寫Page.OnError()來檢測HTTP Code(相應代碼)是否為400來處理,這里不再贅述,代碼如下:

  1. System.Configuration.Configuration   
  2. config = WebConfigurationManager.  
  3. OpenWebConfiguration("~");  
  4. HttpRuntimeSection section = config.GetSection  
  5. ("system.web/httpRuntime"as HttpRuntimeSection;  
  6. double maxFileSize = Math.Round  
  7. (section.MaxRequestLength / 1024.0, 1);  
  8. string errorString = string.Format("Make sure   
  9. your file is under {0:0.#} MB.", maxFileSize);  
  1. protected override void OnError(EventArgs e)  
  2. {  
  3. HttpContext ctx = HttpContext.Current;  
  4. Exception exception = ctx.Server.GetLastError ();  
  5.  
  6. string errorString =   
  7.  "
    Offending URL: "
     + ctx.Request.Url.ToString () +  
  8.  "
    Source: "
     + exception.Source +   
  9.  "
    Message: "
     + exception.Message +  
  10.  "
    Stack trace: "
     + exception.StackTrace;  
  11.  
  12. ctx.Response.Write (errorString);  
  13.  
  14. ctx.Server.ClearError ();  
  15.  
  16. base.OnError (e);  
  17. }  

對于文件上傳的功能需要較為特別的需求——例如進度條提示,ASP.NET封裝的控件〈asp:FileUpload /〉就無能為力了。  

好的解決方案

Robert Bazinet建議,最好的解決方案是使用RIA,大多數情況下,建議用Silverlight或Flash的上傳組件來替代傳統的FileUpload組件,這類組件不只是提供了更好的上傳體驗,也比〈input type="file"〉標簽在頁面上的文本框、按鈕漂亮,這個〈input type="file"〉標簽并不能夠通過CSS添加樣式,不過也有人嘗試去解決了。至今為止并沒有什么商業(yè)上傳組件使用了Silverlight,不過這里有演示了用Silverlight進行多文件上傳的示例程序。當然使用Silverlight就可以很輕松的實現多線程上傳,斷點續(xù)傳這種功能了,這些都不是我要詳細討論的內容,如果有需要可以自己去看下。

可選擇的解決方案

使用〈input type="file" /〉標簽所能提供的支持非常有限,一些特殊需求我們不能實現——或者說是無法輕易地、直接地實現。所以為了實現這樣的功能我們每次都要繞一個大大的彎。為了避免每次實現相同功能時都要費神費時地走一遍彎路,市面上或者開源界出現了各種上傳組件,上傳組件提供了封裝好的功能,使得我們在實現文件上傳功能時變得輕松了很多。例如幾乎所有的上傳組件都直接或間接地提供了進度提示的功能,有的提供了當前的百分比數值,有的則直接提供了一套UI;有的組件只提供了簡單的UI,有的卻提供了一整套上傳、刪除的管理界面。此外,有的組件還提供了防止客戶端惡意上傳的能力。

我覺得最好的辦法是在HttpModule里分塊讀取文件并且保持頁面激活的狀態(tài),這樣就不會超時,同時也可以跟蹤進度或者取消上傳,或者通過HttpHandler實現,在通過進度條給用戶充分提示的同時,也讓開發(fā)人員能夠更好地控制文件大小以及上傳過程中可能出現的異常。上傳組件都是用這些辦法的,我們的選擇有:

  1. FileUploader.NET (MediaChase公司,$310以上)   
  2. RadUpload (Telerik公司,$249)   
  3. NeatUpload (免費,遵守LGPL協議)   
  4. ······  

NeatUpload是在ASP.NET Pipeline的BeginRequest事件中截獲當前的HttpWorkerRequest對象,然后直接調用其ReadEntityBody等方法獲取客戶端傳遞過來的數據流,并加以分析和處理。并通過使用新的請求進行輪詢來獲取當前上傳的狀態(tài)。關于NeatUpload和其他開源組件的介紹可以參看JeffreyZhao的在ASP.NET應用程序中上傳文件,當然他還說了Memba Velodoc XP Edition和swfupload,寫的非常棒!

HttpWorkerRequest實現介紹

利用隱含的HttpWorkerRequest,用它的GetPreloadedEntityBody和ReadEntityBody方法從IIS為ASP.NET建立的pipe里分塊讀取數據可以實現文件上傳。實現方法如下:

  1. IServiceProvider provider=(IServiceProvider)  
  2. HttpContext.Current;  
  3. HttpWorkerRequest wr=(HttpWorkerRequest)  
  4. provider.GetService(typeof(HttpWorkerRequest));  
  5. byte[] bs=wr.GetPreloadedEntityBody();  
  6. if(!wr.IsEntireEntityBodyIsPreloaded())  
  7. {  
  8. int n=1024;  
  9. byte[] bs2=new byte[n];  
  10. while(wr.ReadEntityBody(bs2,n) 〉0)  
  11. {  
  12. }  
  13. }  

結論

ASP.NET大文件上傳是一個不完善和有缺陷的領域,相信在不久會得到提高和發(fā)展,如果你已經解決了,說明你在一個好公司,否則你可以考慮使用第三方產品來解決了。文件上傳的問題,我們都能夠找到很多種不同的方法來解決,挑戰(zhàn)在于找出不同做法的利弊然后找到一個適用于自己項目的方案,這不僅僅是在文件上傳這一個方面!

【編輯推薦】

  1. ASP.NET環(huán)境下的Shell函數
  2. 在ASP.NET中向數據庫批量插入數據
  3. ASP.NET用Post方式向網頁發(fā)送數據
  4. ASP.NET 2.0部署WEB應用程序淺析
  5. ASP.NET中的HttpWorkerRequest對像
責任編輯:冰荷 來源: cnblogs
相關推薦

2009-07-20 16:09:39

2009-07-21 16:05:58

ASP.NET大文件上

2009-07-24 15:07:56

ASP.NET上傳文件

2010-02-05 08:32:32

ASP.NET MVC

2009-07-29 10:02:49

ASP.NET上傳

2009-10-30 14:03:59

ASP.NET上傳文件

2009-07-27 17:32:39

Web ServiceASP.NET

2009-07-21 13:01:07

ASP.NET上傳文件

2009-07-29 16:08:07

ASP和ASP.NET

2009-07-28 16:57:50

ASP.NET Ses

2009-07-24 10:14:22

ASP.NET開發(fā)

2009-08-05 11:14:33

ASP.NET ISA

2009-07-22 16:25:41

ASP.NET AJA

2009-07-23 13:19:51

2017-03-06 11:13:57

ASP.NETCoreMVC

2009-07-21 16:23:57

2009-07-30 14:18:02

ASP.NET實例教程

2009-08-04 11:46:09

2023-09-06 08:33:30

2015-03-03 13:15:19

ASP.NET大文件下載實現思路
點贊
收藏

51CTO技術棧公眾號