最近做项目中遇到很多问题,比如带进度条的文件上传,看了网上很多资料还没找到真正意义上的ASP.NET实现进度条上传(可能是我没找到),下面我来跟大家分享一下我实现的这个程序。
首先看下界面效果,当然你可以完全修改界面为你自己所用。
先解释一下这个程序,该程序采用了jquery框架,实现了小文件上传,不超过80Mb,可以在web.config文件中进行相应的配置,但是有个最大值,具体需要查看msdn。开发环境采用visual studio 2013 .net framework 4.5,运行的时候大家注意一下是否满足要求,好了,下面直入正题。
先来看看实现原理。基本原理:一个页面进行文件上传,另外一个页面去监听这个文件上传了多少。
这里面有两个地方需要解释一下:第一个,如何知道监听的这个文件就是上传的这个文件?实现机制很简单,就是让asp.net产生一个唯一的guid,这个id序号是唯一的,通过ajax取出来赋值给一个隐藏字段;第二个,如何获取guid标志的文件信息?通过asp.net缓存机制实现,上传的过程中,不断的将上传信息往缓存里面写,直到文件上传完成,而在另外一个通过guid获取缓存的信息,信息包括你想要的信息,比如上传了多少字节、消耗了多长时间等。好了,要点就解释到这里,有疑问的话给我留言。
下面来说说具体的实现:
文件目录结构如下:
index.htm就是文件上传页面,提交form给UploadHandler目录下的Default.aspx,以实现文件上传。
ProgressHandler目录下三个文件为Abort.ashx、GenericGuid.ashx,Handler.ashx功能分别为:根据Guid取消正在上传的文件,生成Guid,根据Guid获取上传信息。
第一步:建立index.htm页面,这个上传页面,需要注意的就是需要一个隐藏的iframe,并且名字为form提交的目标。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
< head >
< title >ASP.NET Ajax文件上传进度条示例</ title >
< meta name = "author" content = "李检全" />
< link href = "Styles/base.css" rel = "stylesheet" type = "text/css" />
< script src = "Scripts/jquery-1.4.2.min.js" type = "text/javascript" ></ script >
< script src = "Scripts/jquery-ui-1.8.2.custom.min.js" type = "text/javascript" ></ script >
< script src = "Scripts/ljq.lib.js" type = "text/javascript" ></ script >
< script src = "Scripts/Ajax/GuidGet.js" type = "text/javascript" ></ script >
< script src = "Scripts/Ajax/ajax-progress-upload.js" type = "text/javascript" ></ script >
</ head >
< body >
< div id = "upload_demo" >
< div class = "title" >ASP.NET Ajax 文件上传进度条示例</ div >
< form action = "UploadHandler/Default.aspx" enctype = "multipart/form-data" method = "post" target = "upload_hidden_iframe" >
< input id = "guid" name = "guid" value = "" type = "hidden" />
< p >*本程序适合小文件上传,不超过80Mb</ p >
< p >文件地址</ p >
< input name = "upload_file" type = "file" />
< br />
< p >文件描述</ p >
< textarea name = "description_file" ></ textarea >
< br />
< br />
< input type = "submit" value = "上传文件" />
</ form >
</ div >
< div id = "back_panel" ></ div >
< div id = "upload_panel" >
< div id = "upload_title" >文件上传</ div >
< div id = "upload_content" >
< ul >
< li id = "finished_percent" >正在准备上传...</ li >
< li >< div id = "upload_bar" >< div id = "upload_progress" ></ div ></ div ></ li >
< li id = "upload_speed" ></ li >
< li id = "upload_costTime" ></ li >
< li id = "upload_fileSize" ></ li >
< li id = "upload_fileName" ></ li >
</ ul >
< div id = "upload_detail" ></ div >
< div id = "upload_choose" >
< span id = "upload_cancel" >取消</ span >< span id = "upload_submit" >确定</ span >
</ div >
</ div >
</ div >
< iframe name = "upload_hidden_iframe" style = "display:none;" ></ iframe >
</ body >
</ html >
|
第二步,创建GenerateGuid.ashx文件,作用就是生成唯一的Guid。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
<%@ WebHandler Language="C#" Class="ProgressHandler.Handler" %>
using System;
using System.Web;
using System.Xml.Linq;
namespace ProgressHandler
{
public class Handler : IHttpHandler
{
/// < summary >
/// 获得上传文件的GUID
/// </ summary >
/// < param name = "context" >当前请求实体</ param >
/// < creattime >2015-06-28</ creattime >
/// < author >FreshMan</ author >
public void ProcessRequest(HttpContext context)
{
context.Response.Charset = "utf-8";
context.Response.ContentType = "application/xml";
var guid = Guid.NewGuid().ToString();
var doc = new XDocument();
var root = new XElement("root");
var xGuid = new XElement("guid", guid);
root.Add(xGuid);
doc.Add(root);
context.Response.Write(doc.ToString());
context.Response.End();
}
public bool IsReusable
{
get { return false; }
}
}
}
|
第三步,创建Default.aspx文件,用于提交表单时上传文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
using System;
namespace UploadHandler
{
public partial class UploadHandlerDefault : System.Web.UI.Page
{
protected void Page_Load( object sender, EventArgs e)
{
string guid = Request.Params[ "guid" ];
UploadUtil utilHelp = new UploadUtil( this , guid);
utilHelp.Upload();
}
}
}
|
上传核心代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
using System;
using System.Web;
using System.IO;
using System.Configuration;
using System.Web.UI;
using System.Web.Caching;
using System.Threading;
public class UploadUtil
{
private Stream _reader;
private FileStream _fStream;
private const int Buffersize = 10000;
private readonly string _filePath = new Page().Server.MapPath(ConfigurationManager.AppSettings[ "upload_folder" ]);
private readonly Page _page;
private readonly string _guid;
public UploadUtil(Page page, string guid)
{
_page = page;
_guid = guid;
}
public void Upload()
{
if (_page.Request.Files.Count > 0)
{
DoUpload(_page.Request.Files[0]);
}
}
private void DoUpload(HttpPostedFile postedFile)
{
bool abort = false ;
string uploadFilePath = _filePath + DateTime.Now.ToFileTime()+ "//" ;
if (!Directory.Exists(uploadFilePath))
{
Directory.CreateDirectory(uploadFilePath);
}
string uploadFileName = postedFile.FileName;
DownloadingFileInfo info = new DownloadingFileInfo(uploadFileName, postedFile.ContentLength, postedFile.ContentType);
object fileObj = HttpContext.Current.Cache[_guid];
if (fileObj != null )
{
HttpContext.Current.Cache.Remove(_guid);
}
HttpContext.Current.Cache.Add(_guid, info, null , DateTime.Now.AddDays(1), TimeSpan.Zero, CacheItemPriority.AboveNormal, null );
DateTime begin=DateTime.Now.ToLocalTime();
_fStream = new FileStream(uploadFilePath + uploadFileName, FileMode.Create);
_reader = postedFile.InputStream;
byte []buffer= new byte [Buffersize];
int len = _reader.Read(buffer,0,Buffersize);
while (len > 0&&!abort)
{
_fStream.Write(buffer,0,len);
DateTime end = DateTime.Now.ToLocalTime();
info.CostTime = ( long )(end - begin).TotalMilliseconds;
info.FileFinished += len;
//模拟延时用,实际应用的时候注销他
Thread.Sleep(1000);
HttpContext.Current.Cache[_guid] = info;
abort=((DownloadingFileInfo)HttpContext.Current.Cache[_guid]).Abort;
len = _reader.Read(buffer,0,Buffersize);
}
_reader.Close();
_fStream.Close();
if (abort)
{
if (File.Exists(uploadFilePath + uploadFileName))
{
File.Delete(uploadFilePath + uploadFileName);
}
}
}
}
|
第四步,创建Handler.ashx文件,用于查看文件上传情况。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
<%@ WebHandler Language= "C#" Class= "ProgressHandler.Handler" %>
using System.Web;
using System.Xml.Linq;
namespace ProgressHandler
{
public class Handler : IHttpHandler
{
/// <summary>
/// 获得上传文件的进度
/// </summary>
/// <param name="context">当前请求实体</param>
/// <creattime>2015-06-28</creattime>
/// <author>FreshMan</author>
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/xml" ;
context.Response.Charset = "utf-8" ;
var guid = context.Request.Form[ "guid" ];
var info = context.Cache[guid] as DownloadingFileInfo;
var doc = new XDocument();
var root = new XElement( "root" );
if (info != null )
{
var fileName = new XElement( "fileName" , info.FileName);
var fileFinished = new XElement( "fileFinished" , info.FileFinished);
var fileSize = new XElement( "fileSize" , info.FileSize);
var costTime = new XElement( "costTime" , info.CostTime);
var fileState = new XElement( "fileState" , info.FileState);
var speed = new XElement( "speed" , info.Speed);
var percent = new XElement( "percent" , info.Percent);
var abort = new XElement( "abort" , false );
root.Add(fileName);
root.Add(fileFinished);
root.Add(fileSize);
root.Add(costTime);
root.Add(fileState);
root.Add(speed);
root.Add(percent);
if (info.Abort)
{
abort.Value = info.Abort.ToString();
context.Cache.Remove(guid);
}
if (info.FileState == "finished" )
{
context.Cache.Remove(guid);
}
}
else
{
var none = new XElement( "none" , "no file" );
root.Add(none);
}
doc.Add(root);
context.Response.Write(doc.ToString());
context.Response.End();
}
public bool IsReusable
{
get { return false ; }
}
}
}
|
第五步,创建Abort.ashx文件,用于取消上传。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
<%@ WebHandler Language= "C#" Class= "ProgressHandler.Abort" %>
using System.Web;
using System.Xml.Linq;
namespace ProgressHandler
{
public class Abort : IHttpHandler
{
/// <summary>
/// 取消上传处理程序
/// </summary>
/// <param name="context">当前请求实体</param>
/// <creattime>2015-06-28</creattime>
/// <author>FreshMan</author>
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/xml" ;
context.Response.Charset = "utf-8" ;
var guid = context.Request.Form[ "guid" ];
var abort = ! string .IsNullOrEmpty(context.Request.Form[ "abort" ]);
var info = context.Cache[guid] as DownloadingFileInfo;
if (info != null )
{
info.Abort = abort;
context.Cache[guid] = info;
}
var doc = new XDocument();
var root = new XElement( "root" );
var flag = new XElement( "flag" , info == null ? "false" : "true" );
root.Add(flag);
doc.Add(root);
context.Response.Write(doc.ToString());
context.Response.End();
}
public bool IsReusable
{
get { return false ; }
}
}
}
|
好了,下面就是编写javascript脚本了,我引用了jquery这个框架,另外还用了ui框架。
核心代码是ajax-progress-upload.js文件,另外还有一个获取guid的文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
$(document).ready( function () {
var _guid_url = "ProgressHandler/GenerateGuid.ashx" ;
var _progress_url = "ProgressHandler/Handler.ashx" ;
var _abort_url = "ProgressHandler/Abort.ashx" ;
var _target = "#guid" ;
var _guid = "" ;
var _cancel = false ;
var _timer;
LJQ.setGuid(_target, _guid_url);
$( "#upload_panel" ).draggable({ handle: "#upload_title" });
$( "#upload_choose span" ).hover( function () {
$( this ).css({
"color" : "#f6af3a" ,
"border" : "1px solid #e78f08"
});
}, function () {
$( this ).css({
"color" : "#1c94cd" ,
"border" : "1px solid #ddd"
});
});
$( "#upload_cancel" ).click( function () {
$.ajax({
url: _abort_url,
data: { guid: _guid, abort: true },
dataType: "xml" ,
type: "post" ,
success: function () {
$( "#upload_panel" ).fadeOut( 'fast' );
$( "#back_panel" ).fadeOut(1000);
window.clearInterval(_timer);
}
});
});
$( "#upload_submit" ).click( function () {
$( "#upload_panel" ).fadeOut( 'fast' );
$( "#back_panel" ).fadeOut( "1000" );
});
$( "form" ).submit( function () {
_guid = $(_target).val();
if ($( "input[name='upload_file']" ).val() == "" ) {
alert( "未指定上传文件!" );
return false ;
}
$( "#upload_progress" ).css( "width" , "0%" );
$( "#finished_percent" ).html( "准备上传..." );
$( "#upload_speed" ).html( "" );
$( "#upload_fileName" ).html( "" );
$( "#upload_fileSize" ).html( "" );
$( "#upload_costTime" ).html( "" );
var _option = {
url: _progress_url,
data: { guid: _guid },
dataType: "xml" ,
type: "post" ,
beforeSend: function () {
$( "#back_panel" ).fadeTo( 'fast' , '0.5' );
$( "#upload_panel" ).fadeIn( '1000' );
},
success: function (response) {
if ($(response).find( "root abort" ).text() == "true" ) {
$( "#upload_panel" ).fadeOut( 'fast' );
$( "#back_panel" ).fadeOut(1000);
window.clearInterval(_timer);
}
else if ($(response).find( "root none" ).text() == "no file" ) {
}
else {
var _percent = ($(response).find( "root percent" ).text() * 100);
var _speed = $(response).find( "root speed" ).text();
var _fileSize = $(response).find( "root fileSize" ).text();
var _upload_costTime = $(response).find( "root costTime" ).text();
if (parseInt(_speed) < 1024) {
_speed = LJQ.toFix(_speed) + "Kb" ;
} else {
_speed = LJQ.toFix(_speed / 1024) + "Mb" ;
}
if (parseInt(_fileSize) / 1024 < 1024) {
_fileSize = LJQ.toFix(_fileSize / 1024) + "Kb" ;
} else if (parseInt(_fileSize) / 1024 / 1024 < 1024) {
_fileSize = LJQ.toFix(_fileSize / 1024 / 1024) + "Mb" ;
} else {
_fileSize = LJQ.toFix(_fileSize / 1024 / 1024 / 1024) + "Gb" ;
}
if (_upload_costTime < 1000) {
_upload_costTime = _upload_costTime + "毫秒" ;
} else if (_upload_costTime / 1000 < 60) {
_upload_costTime = parseInt(_upload_costTime / 1000) + "秒" + _upload_costTime % 1000 + "毫秒" ;
} else {
_upload_costTime = parseInt(_upload_costTime / 1000 / 60) + "分" + parseInt((_upload_costTime % 60000) / 1000) + "秒" + _upload_costTime % 1000 + "毫秒" ;
}
$( "#upload_progress" ).css( "width" , parseInt(_percent) + "%" );
$( "#finished_percent" ).html( "完成百分比:" + LJQ.toFix(_percent) + "%" );
$( "#upload_speed" ).html( "上传速度:" + _speed + "/sec" );
$( "#upload_fileName" ).html( "文件名称:" + $(response).find( "root fileName" ).text());
$( "#upload_fileSize" ).html( "文件大小:" + _fileSize);
$( "#upload_costTime" ).html( "上传耗时:" + _upload_costTime);
if (_percent >= 100) {
window.clearInterval(_timer);
$( "#finished_percent" ).html( "<span style='color:green;'>文件上传完成</span>" );
}
if (_cancel) {
window.clearInterval(_timer);
}
}
},
error: function () { }
};
_timer = window.setInterval( function () { $.ajax(_option); }, 1000);
});
});
|
以上为代码的主要部分。asp.net单文件带进度条上传,不属于任务控件,也不是flash类型的上传,完全是asp.net、js、css实现上传。源码为开发测试版,需要使用的亲需要注意修改配置文件。
项目源码下载请点击这里:asp_net_progressbar.rar