當前位置:才華齋>設計>網頁設計>

通過Asp.Net的伺服器控制元件上傳檔案總結

網頁設計 閱讀(1.58W)

相信通過的伺服器控制元件上傳檔案在簡單不過了,通過AjaxToolkit控制元件實現上傳進度也不是什麼難事,為什麼還要自己辛辛苦苦來 實現呢?我並不否認”拿來主義“,只是我個人更喜歡凡是求個所以然。本篇將闡述通過Html,IHttpHandler和 IHttpAsyncHandler實現檔案上傳和上傳進度的原理,希望對你有多幫助。

通過的伺服器控制元件上傳檔案總結

效果圖:

本文涉及到的知識點:

1.前臺用到Html,Ajax,JQuery,JQuery UI

2.後臺用到一般處理程式(IHttpHandler)和一般非同步處理程式(IHttpAsyncHandler),並涉及到”推模式“

一、建立Html網頁

1、在建立的Web工程中新增一個Html檔案,命名為,在標頭檔案中引入JQuery,JQuery UI

複製程式碼 程式碼如下:

二、實現檔案上傳

新增一個一般處理程式,命名為

複製程式碼 程式碼如下:

public void ProcessRequest(HttpContext context)

{

//如果提交的檔名是空,則不處理

if (t == 0 || llOrWhiteSpace(s[0]Name))

return;

//獲取檔案流

Stream stream = s[0]tStream;

//獲取檔名稱

string fileName = ileName(s[0]Name);

//宣告位元組陣列

byte[] buffer;

//為什麼是4096呢?這是作業系統中最小的分配空間,如果你的檔案只有100個位元組,其實它佔用的空間是4096個位元組

int bufferSize = 4096;

//獲取上傳檔案流的總長度

long totalLength = th;

//已經寫入的位元組數,用於做上傳的百分比

long writtenSize = 0;

//建立檔案

using (FileStream fs = new FileStream(@"C:" + fileName, te, e))

{

//如果寫入檔案的位元組數小於上傳的總位元組數,就一直寫,直到寫完為止

while (writtenSize < totalLength)

{

//如果剩餘的位元組數不小於最小分配空間

if (totalLength - writtenSize >= bufferSize)

{

//用最小分配空間建立新的位元組陣列

buffer = new byte[bufferSize];

}

else

//用剩餘的位元組數建立位元組陣列

buffer = new byte[totalLength - writtenSize];

//讀取上傳的檔案到位元組陣列

(buffer, 0, th);

//將讀取的位元組陣列寫入到新建的檔案流中

e(buffer, 0, th);

//增加寫入的位元組數

writtenSize += th;

//計算當前上傳檔案的百分比

long percent = writtenSize * 100 / totalLength;

}

}

}

在form中新增action和method屬性,修改之後的

複製程式碼 程式碼如下:

這樣檔案上傳就完成了。

三、實現檔案上傳的進度顯示

我的思路:

檔案上傳的處理過程中,是不可以在處理過程中將資訊傳回客戶端的,只有當所有的處理都完畢之後才會傳回客戶端,所以如果是在上面的處理程式中寫 入e(percent);是不可能得到處理的過程,只能等到處理結束後,客戶端一次性得到所有的值。

要想得到處理過程中的值,我的解決是這樣,在檔案上傳時,要開啟另一個請求,來獲取進度資訊。而這個請求是非同步的,我指的是客戶端非同步請求和服 務端非同步處理。因為要涉及到兩個不同的請求處理程式之間資訊的傳遞,將"處理檔案上傳的程式"得到的進度資訊傳遞給"處理進度請求的程式",而"處理進度 請求的處理程式"要依賴於"處理檔案上傳的處理程式"。處理圖:

首先客戶端同時(幾乎是)發出兩個請求,一個是檔案上傳,一個是進度請求。由於"處理請求進度的程式"是非同步處理的,當該程式沒有資訊發給客戶 端時,我們讓它處於等待狀態,這裡有點像Tcp,這樣客戶端跟伺服器就一直處於連線狀態。當"處理檔案上傳的程式"開始處理時,通過把進度值賦值給"處理 請求進度程式"的非同步操作的狀態,並觸發"處理請求進度的程式"返回值給客戶端。客戶端獲取進度值,並處理。這樣一次請求進度值的請求就結束了,我們知道 伺服器是不會主動給客戶端傳送資訊的,只有客戶端請求,伺服器才會響應。顯然,要想在檔案儲存的過程中向客戶端傳送進度資訊,客戶端得到每得到一個返回結 果,都是一次請求。為了得到連續的'請求值,客戶端再向"處理請求進度的程式"發出請求,依次迴圈,知道檔案上傳結束。

技術實現:

非同步處理用到介面IHttpAsyncHandler,新建一個一般處理程式,命名為,將預設的介面改為IHttpAsyncHandler

複製程式碼 程式碼如下:

public class RequestProgressAsyncHandler : IHttpAsyncHandler

{

public void ProcessRequest(HttpContext context)

{

}

public bool IsReusable

{

get

{

return false;

}

}

#region IHttpAsyncHandler 成員

public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)

{

throw new NotImplementedException();

}

public void EndProcessRequest(IAsyncResult result)

{

throw new NotImplementedException();

}

#endregion

}

BeginProcessRequest和EndProcessRequest是兩個核心的方法,其他的兩個不用處理。當該處理程式處理請求 時,BeginProcessRequest是第一個被呼叫的函式,返回一個包含非同步狀態資訊的物件,該物件是IAsyncResult型別,是實現非同步 的關鍵,用於控制什麼時候呼叫EndProcessRequest來結束處理程式的等待狀態,BeginProcessRequest被呼叫之後,程式就 處於等待狀態。EndProcessRequest是在結束請求時的處理函式,通過該函式可以向客戶端寫入資訊。

實現介面IAsyncResult

複製程式碼 程式碼如下:

public class AsyncResult : IAsyncResult

{

// 標示非同步處理的狀態

private bool isComplete = false;

//儲存非同步處理程式中的Http上下文

private HttpContext context;

//非同步回撥的委託

private AsyncCallback callback;

///

/// 獲取或設定儲存下載檔案的百分比數值部分

///

public long PercentNumber;

public AsyncResult(HttpContext context, AsyncCallback callback)

{

ext = context;

back = callback;

}

///

/// 向客戶端寫入資訊

///

public void Send()

{

e(PercentNumber);

}

///

/// 完成非同步處理,結束請求

///

public void DoCompleteTask()

{

if (callback != null)

callback(this);//會觸發處理程式中的EndProcessRequest函式,結束請求

mplete = true;

}

#region IAsyncResult 成員

public object AsyncState

{

get { return null; }

}

public Handle AsyncWaitHandle

{

get { return null; }

}

public bool CompletedSynchronously

{

get { return false; }

}

public bool IsCompleted

{

get { return isComplete; }

}

#endregion

}

修改 檔案:

複製程式碼 程式碼如下:

public class RequestProgressAsyncHandler : IHttpAsyncHandler

{

///

/// 儲存非同步處理狀態資訊的集合

///

public static ListAsyncResults = new List();

public void ProcessRequest(HttpContext context)

{

}

public bool IsReusable

{

get

{

return false;

}

}

#region IHttpAsyncHandler 成員

public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)

{

AsyncResult result = new AsyncResult(context, cb);

(result);

return result;

}

public void EndProcessRequest(IAsyncResult result)

{

//保證集合中只用一個元素

r();

AsyncResult ar = (AsyncResult)result;

();

}

#endregion

}

在新增如下程式碼:

複製程式碼 程式碼如下:

private static void SendPercentToClient(long percent)

{

//當上傳完畢後,保證處理程式能向客戶端傳回

while (t == 0 && percent == 100)

{

}

//因為本處理程式和"處理請求進度的程式"是併發的,不能保證cResults一定含有子項

if (t != 0)

{

cResults[0]entNumber = percent;

cResults[0]mpleteTask();

}

}

在函式ProcessRequest中加入以上方法:

複製程式碼 程式碼如下:

...

...

//計算當前上傳檔案的百分比

long percent = writtenSize * 100 / totalLength;

SendPercentToClient(percent);

服務端OK!修改客戶端,新增JS處理函式:

複製程式碼 程式碼如下:

function RequestProgress() {

$("", function (data, status) {

if (status == "success") {

$("#progressValue")(data + "%");

data = parseInt(data);

$("#progressBar")ressbar({ value: data });//JQuery UI 設定進度條值

//如果進度不是 100,則重新請求

if (data != 100) {

RequestProgress();

}

}

});

}

在form中新增事件omsubmit的處理函式為RequestProgress

複製程式碼 程式碼如下:

補充幾點:

1.預設允許的上傳檔案的大小是4M,可以在ig中修改其大小限制

複製程式碼 程式碼如下:

maxRequestLength的單位是KB

2.在IE 8.0測試中,在檔案上傳完畢後,狀態列還處於請求中

反正不是後臺還在請求,這個放心,只要把滑鼠在按鈕和瀏覽上面來回移動幾下就沒了,可能是JQuery UI 的問題。FF和Chrom下沒這個問題,就是顯示效果會有點差,但是上傳沒問題的。

原始碼下載: