通過Asp.Net的服務器控件上傳文件總結
相信通過的服務器控件上傳文件在簡單不過了,通過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下沒這個問題,就是顯示效果會有點差,但是上傳沒問題的。
源代碼下載:
-
如何獲取PHP數組的鍵與值呢
array_keys($array);//獲取數組(字典)的所有鍵值,返回一個鍵值數組。array_values($array)://獲取數組的所有value值,飯回一個數組。<?php$json='{"a":1,"b":2,"c":3,"d":4,"e":5}';//註明:value不帶雙引號時,其值只能是數字。【!!!注意:大括號兩邊只能是單引號,...
-
HTML5教程:畫布Canvas基礎知識講解
Canvas是HTML5最讓人期待的特性之一,目前已獲得大部分Web瀏覽器支持Canvas可以幫助創建遊戲、增強圖形用户界面。下面YJBYS小編為大家帶來畫布Canvas基礎知識,希望對大家學習有所幫助!HTML5規範引進了很多新特性,其中最令人期待的之一就是Canvas元素。HTML5Canvas...
-
JavaScript基本語法分析
一、JavaScript基本語法。(一)數據類型與變量類型。整數,小數,佈局,字符串,日期時間,數組強制轉換:parseInt()parseFloat()isNaN()(二)數組var數組名=newArray([長度]);//“假冒”數組th-長度a[下標]=值。a[下標](三)函數複製代碼代碼如下:function函數名(形參){}function...
-
網頁設計10大靈感來源介紹
不僅僅只有網頁設計能激發我們創建出色網站的動力,幾乎我們身邊的任何事都會有此作用。以下是本站小編搜索整理的關於網頁設計10大靈感來源介紹,供參考借鑑,希望對大家有所幫助!想了解更多相關信息請持續關注我們應屆畢業生考試網!自然圖01圖02思考設計的最佳場所...