欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

asp.net单文件带进度条上传的解决方案

程序员文章站 2024-02-17 10:10:52
最近做项目中遇到很多问题,比如带进度条的文件上传,看了网上很多资料还没找到真正意义上的asp.net实现进度条上传(可能是我没找到),下面我来跟大家分享一下我实现的这个程序...

最近做项目中遇到很多问题,比如带进度条的文件上传,看了网上很多资料还没找到真正意义上的asp.net实现进度条上传(可能是我没找到),下面我来跟大家分享一下我实现的这个程序。
首先看下界面效果,当然你可以完全修改界面为你自己所用。

asp.net单文件带进度条上传的解决方案

先解释一下这个程序,该程序采用了jquery框架,实现了小文件上传,不超过80mb,可以在web.config文件中进行相应的配置,但是有个最大值,具体需要查看msdn。开发环境采用visual studio 2013 .net framework 4.5,运行的时候大家注意一下是否满足要求,好了,下面直入正题。
先来看看实现原理。基本原理:一个页面进行文件上传,另外一个页面去监听这个文件上传了多少。
这里面有两个地方需要解释一下:第一个,如何知道监听的这个文件就是上传的这个文件?实现机制很简单,就是让asp.net产生一个唯一的guid,这个id序号是唯一的,通过ajax取出来赋值给一个隐藏字段;第二个,如何获取guid标志的文件信息?通过asp.net缓存机制实现,上传的过程中,不断的将上传信息往缓存里面写,直到文件上传完成,而在另外一个通过guid获取缓存的信息,信息包括你想要的信息,比如上传了多少字节、消耗了多长时间等。好了,要点就解释到这里,有疑问的话给我留言。
下面来说说具体的实现:
文件目录结构如下:

 asp.net单文件带进度条上传的解决方案

index.htm就是文件上传页面,提交form给uploadhandler目录下的default.aspx,以实现文件上传。
progresshandler目录下三个文件为abort.ashx、genericguid.ashx,handler.ashx功能分别为:根据guid取消正在上传的文件,生成guid,根据guid获取上传信息。
第一步:建立index.htm页面,这个上传页面,需要注意的就是需要一个隐藏的iframe,并且名字为form提交的目标。

<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> 
 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<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。

<%@ 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文件,用于提交表单时上传文件。

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(); 
  } 
 } 
} 

上传核心代码:

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文件,用于查看文件上传情况。

<%@ 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文件,用于取消上传。

 <%@ 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的文件。

$(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实现上传。源码为开发测试版,需要使用的亲需要注意修改配置文件。

项目源码下载请点击这里: