使用经典ASP.NET和C#实现带进度条的多文件上传






4.33/5 (8投票s)
在 Web 应用程序中,上传文件时显示进度条是很有必要的。本文将帮助您在 ASP.NET 2.0 中为单文件和多文件上传创建进度条。
引言
本文为读者提供了一个关于如何在基于 Web 的应用程序中创建单文件/多文件上传进度条的良好思路。我们之前的一个项目要求显示一个连续的进度条以及上传百分比。本文将为您提供关于如何使用 ASP.NET 2.0 和 .NET Framework 2.0 创建此类控件的宝贵信息。此外,由于该解决方案使用了 IFrame 来加载文件上传控件,因此部署该控件的页面不会发生回发。用户可以在上传过程中自由访问页面的其他部分。
背景
我的初步想法是,在服务器端计算进度量,并使用 JavaScript 定时函数通过 XMLHttpRequest
对象读取服务器端的进度量,从而从客户端更新进度条。但这效果不佳,因为它要么显示 0%,要么显示完整的 100%,但不是连续的进度。我使用了 Mozilla Firebug 来追踪 XMLHttpRequest
对象的请求模式。出于某种原因,XMLHttpRequest
会被排队,直到服务器端事件处理程序完成其执行,在这种情况下是上传完成,所以它要么在服务器端上传开始之前发出请求,要么在服务器端上传完成后发出请求。因此,进度条要么显示 0% 或 100%。
我想感谢 Mr. Munur Shaik:http://www.c-sharpcorner.com/UploadFile/munnamax/ProgressBar07062007122251PM/ProgressBar.aspx 的创意,我已将其用于创建我的进度条。此外,我想向我们的架构师 Anil Sistla 表示感谢,感谢他对我的支持,使我得以完成此解决方案。我希望本文能为正在寻找类似解决方案的人节省大量时间。
使用代码
下面是源代码结构。UploadProgressBar.ascx 文件是用户控件,它显示一个带有“添加/移除”按钮的单文件上传控件。“添加”按钮会添加多个文件上传控件,“移除”按钮则一次移除一个文件上传控件。
下图显示了初始文件上传屏幕。FileUploadIframe.aspx 包含一个简单的 HTML IFrame 标签,用于加载控件页面(FileUpload.aspx)。这里使用 IFrame 是因为放置多文件上传控件的主页面在按下上传按钮时,不应该发生回发。
文件上传过程中,进度条显示如下:
以下是创建进度条的代码:
public void CreateProgress(HttpFileCollection fileCollection)
{
//string fileName, int id, string progressAmount
StringBuilder sbProgress = new StringBuilder();
sbProgress.Append("<html><head><LINK REL=StyleSheet " +
"HREF='StyleSheet1.css' TYPE='text/css' /></head> <body>");
sbProgress.Append("<script src='JScript1.js' type='text/javascript'>" +
"</script><table id='mainTable' border='1'>");
for (int i = 0; i < fileCollection.Count; i++)
{
string strProgressBarId = "progressBar" + i;
string strPercentageId = "percentage" + i;
string fileName = fileCollection[i].FileName;
sbProgress.Append("<tr><td><p>" + fileName +
"</p></td><td><div id='xxx' " +
"style='background-color:White; width: 100px;height:15px; " +
"border-color:Black;border-width:thin;border-style:solid'>");
sbProgress.Append("<div class='progressBar' id='" +
strProgressBarId + "' ></div></div></td>" +
"<td><p><div id='" + strPercentageId +
"'></div></p></td></tr>");
}
sbProgress.Append("</table>");
for (int i = 0; i < fileCollection.Count; i++)
{
sbProgress.Append("<script type='text/javascript'> " +
"SetProgressBarProgressAmount(" + i + ",0 );</script>");
}
sbProgress.Append(PrepareTheGridHtml());
sbProgress.Append("</body></html>");
HttpContext.Current.Response.Write(sbProgress.ToString());
HttpContext.Current.Response.Flush();
}
此方法 (CreateProgress()
) 主要将进度条的 HTML 推送到输出流以创建一个空的进度条。在上面的代码中,SetProgressBarProgressAmount(..)
是一个 JavaScript 方法,它接受两个参数:第一个参数是进度条的 ID,如果显示多个进度条,则此 ID 很重要;第二个参数是进度量。随着文件下载到服务器,此进度条将根据下载百分比进行设置,最终在文件下载完成后,它将被设置为 100%。对于多文件上传,将显示多个进度条,每个文件一个,文件将逐个上传到服务器,并且我们可以看到每个文件的进度量。以下是将文件下载到服务器的代码:
public void DownloadTheFileToServer(HttpPostedFile file, int id)
{
Stream stream = null;
FileStream fs = null;
#region File Download Code goes here
try
{
string strFileName = System.IO.Path.GetFileName(file.FileName);
int contentLength = file.ContentLength;
stream = file.InputStream;
long totalUploadSize = stream.Length;
int bufferSize = 0;
//less than 1kB
if (totalUploadSize <= 1024)
{
bufferSize = 1024;
}
//less than 4kB but more than 1kB
else if (bufferSize <= 4096)
{
bufferSize = 4096;
}
//less than 8Kb
else if (bufferSize <=8192)
{
bufferSize = 8192;
}
else
{
bufferSize = 16384;
}
byte[] b = new byte[1024];
int tripDownloadSize = 0;
long totalDownloadedSize = 0;
float Percentage = 0;
bool isNewFile = true;
string fileStoreLocation =
ConfigurationManager.AppSettings["FileStoreLocation"];
fs = new FileStream(fileStoreLocation + strFileName, FileMode.Append);
//Uplaods 8Kb at a time
while ((tripDownloadSize = stream.Read(b, 0, 1024)) > 0)
{
fs.Write(b, 0, tripDownloadSize);
totalDownloadedSize += tripDownloadSize;
Percentage = (int)(totalDownloadedSize * 100) / totalUploadSize;
setProgressBar(id, Percentage.ToString());
System.Threading.Thread.Sleep(100);
isNewFile = false;
}
}
catch (Exception objException)
{
throw objException;
}
finally
{
if (stream != null)
{
stream.Close();
stream.Dispose();
}
if (fs != null)
{
fs.Close();
fs.Dispose();
}
}
#endregion
}
在上述方法中,我根据文件大小编写了逻辑来决定流的缓冲区大小,但这完全取决于开发人员如何设置读取输入流的缓冲区大小(字节数组大小)。本文主要关注如何在文件下载过程中创建/更新进度。在上面的代码中,在 while
循环内,每次都会计算总下载大小,下载的百分比将通过以下公式确定:总下载大小 / 总文件大小 * 100。使用 setProgressBar(id, Percentage)
方法,我们可以为具有 id
的特定进度条设置进度。以下是 SetProgressBar
方法的代码:
public static void setProgressBar(int id, string progressAmount)
{
StringBuilder sb = new StringBuilder();
sb.Append("<body><script type='text/javascript'>" +
"SetProgressBarProgressAmount(" + id + ",'" + progressAmount +
"'); </script></body>");
HttpContext.Current.Response.Write(sb.ToString());
HttpContext.Current.Response.Flush();
}
搜索 `appsettings` 下的 `FileStoreLocation` 条目,并在 `web.config` 文件中将其设置为您计算机上的本地文件夹位置;通过文件上传控件上传的文件将下载到此位置。
免责声明
本文为希望拥有类似进度条的用户提供了一个起点。此控件尚未准备好投入生产环境部署。此进度条控件并未考虑许多因素,例如可以上传到服务器的文件类型等。开发人员有责任确保其符合其需求。对于此控件造成的任何应用程序/产品损坏,我概不负责。我希望开发人员在将此解决方案集成/用于现有应用程序之前对其进行完整评估。