asp.net IHttpAsyncHandler实现带进度条文件上传的问题

peachesTao 2016-03-09 02:42:22
各位好,我用IHttpAsyncHandler实现文件上传带进度显示的功能时,同时打开多个客户端上传时有时会报:

索引超出范围。必须为非负值并小于集合大小。
参数名: index 在 System.ThrowHelper.ThrowArgumentOutOfRangeException()
在 System.Collections.Generic.List`1.RemoveAt(Int32 index)
在 System.Collections.Generic.List`1.Remove(T item)
在 bigFileUploadWithProgress.uploadFileHandler.SendPercentToClient(Int64 percent, String sessionId)

已经知道是 requestProgressAsyncHandler.cs类的requestProgressAsyncHandler.AsyncResults.Remove(ar)这个地方报的错。不知道为什么会报错,我怀疑是共享资源的问题,但我也用lock锁住了啊。还请高手指点。

html代码:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<link href="Styles/jquery-ui-1.8.16.custom.css" rel="stylesheet" type="text/css" />
<script src="Scripts/jquery-1.9.1.js" type="text/javascript"></script>
<script src="Scripts/jquery-ui-1.8.16.custom.min.js" type="text/javascript"></script>

<script type="text/javascript">
$(function () {
$("#submit").button();
$("#fileUpload").button();
//RequestProgress();
});

function RequestProgress() {
var sessionId = $('#sessionId').val();
//alert(sessionId);
$.post("requestProgressAsyncHandler.ashx?sessionId=" + sessionId, function (data, status) {
if (status == "success") {

$("#progressValue").text(data + "%");
data = parseInt(data);
$("#progressBar").progressbar({ value: data });//JQuery UI 设置进度条值
//如果进度不是 100,则重新请求
if (data != 100) {
RequestProgress();
}
}
});
}

</script>

</head>
<body>
<form action="uploadFileHandler.ashx" method="post" id="form" target="frameFileUpload" enctype="multipart/form-data">
<div id="progressBar" style="font-size: 1em;"></div>
<input type="file" id="fileUpload" name="fileUpload" /><span id="progressValue"></span>
<iframe id="frameFileUpload" name="frameFileUpload" style="display:none;"></iframe>
<br />
<input type="submit" value="上传" id="submit" />
输入sessionId:<input type="text" id="sessionId" name="sessionId" value="" />
</form>
<input type="button" id="receiveProgress" value="开始接收进度" onclick="RequestProgress();" />
</body>
</html>

上传文件类uploadFileHandler.ashx.cs


namespace bigFileUploadWithProgress
{
/// <summary>
/// uploadFileHandler 的摘要说明
/// </summary>
public class uploadFileHandler : IHttpHandler
{
private object _syncobject = new object();
public void ProcessRequest(HttpContext context)
{
object sessionId=context.Request.Form["sessionId"];
//如果提交的文件名是空,则不处理
if (context.Request.Files.Count == 0 || string.IsNullOrWhiteSpace(context.Request.Files[0].FileName))
return;
//获取文件流
Stream stream = context.Request.Files[0].InputStream;
//获取文件名称
string fileName = Path.GetFileName(context.Request.Files[0].FileName);
//声明字节数组
byte[] buffer;
//为什么是4096呢?这是操作系统中最小的分配空间,如果你的文件只有100个字节,其实它占用的空间是4096个字节
int bufferSize = 4096;
//获取上传文件流的总长度
long totalLength = stream.Length;
//已经写入的字节数,用于做上传的百分比
long writtenSize = 0;
//创建文件
using (FileStream fs = new FileStream(context.Server.MapPath("Upload")+"\\"+fileName, FileMode.Create, FileAccess.Write))
{
//如果写入文件的字节数小于上传的总字节数,就一直写,直到写完为止
while (writtenSize < totalLength)
{
System.Threading.Thread.Sleep(100);
//如果剩余的字节数不小于最小分配空间
if (totalLength - writtenSize >= bufferSize)
{
//用最小分配空间创建新的字节数组
buffer = new byte[bufferSize];
}
else
//用剩余的字节数创建字节数组
buffer = new byte[totalLength - writtenSize];
//读取上传的文件到字节数组
stream.Read(buffer, 0, buffer.Length);
//将读取的字节数组写入到新建的文件流中
fs.Write(buffer, 0, buffer.Length);
//增加写入的字节数
writtenSize += buffer.Length;
//计算当前上传文件的百分比
long percent = writtenSize * 100 / totalLength;
SendPercentToClient(percent, sessionId.ToString());
}
}
}

public bool IsReusable
{
get
{
return false;
}
}

private void SendPercentToClient(long percent, string sessionId)
{
try
{

//string[] sessionId_Arry=requestProgressAsyncHandler.AsyncResults.

foreach (AsyncResult ar in requestProgressAsyncHandler.AsyncResults)
{
if (ar != null && ar.context != null)
{
if (ar.SessionId == sessionId && ar.context.Response.IsClientConnected)
{
ar.PercentNumber = percent;
ar.DoCompleteTask();
if (requestProgressAsyncHandler.AsyncResults.Contains(ar))
{
lock (_syncobject)
{
requestProgressAsyncHandler.AsyncResults.Remove(ar); //报错的地方。按道理我已经判断了是否包含子项,有的话才会删除,怎么会报找不到子项的错呢?


}
break;
}

}
}
}
//requestProgressAsyncHandler.AsyncResults[0].PercentNumber = percent;
//requestProgressAsyncHandler.AsyncResults[0].DoCompleteTask();

}
catch (Exception ex)
{
writeInLog(ex.Message + " " + ex.StackTrace);
}
}


/// <summary>
/// 写入日志信息
/// </summary>
/// <param name="msg">日志内容</param>
/// <param name="IsAutoDelete">是否自动删除日志</param>
private void writeInLog(string msg)
{
try
{
FileInfo fileinfo = new FileInfo("E:\\uploadFile.txt");

using (FileStream fs = fileinfo.OpenWrite())
{
StreamWriter sw = new StreamWriter(fs);
sw.BaseStream.Seek(0, SeekOrigin.End);
sw.WriteLine("=====================================");
sw.Write("添加日期为:" + DateTime.Now.ToString() + "\r\n");
sw.Write("日志内容为:" + msg + "\r\n");
sw.WriteLine("=====================================");
sw.Flush();
sw.Close();
}
}
catch (Exception ex)
{
ex.ToString();
}
}
}
}

请求进度类requestProgressAsyncHandler.ashx.cs


namespace bigFileUploadWithProgress
{

public class requestProgressAsyncHandler : IHttpAsyncHandler
{
/// <summary>
/// 保存异步处理状态信息的集合
/// </summary>
public static List<AsyncResult> AsyncResults = new List<AsyncResult>();
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);
AsyncResults.Add(result);
return result;
}

public void EndProcessRequest(IAsyncResult result)
{
//保证集合中只用一个元素

AsyncResult ar = (AsyncResult)result;
ar.Send();
}

#endregion
}

public class AsyncResult : IAsyncResult
{
// 标示异步处理的状态
private bool isComplete = false;

//保存异步处理程序中的Http上下文
public HttpContext context;

//异步回调的委托
private AsyncCallback callback;
/// <summary>
/// 获取或设置保存下载文件的百分比数值部分
/// </summary>
public long PercentNumber;
public string SessionId;
public AsyncResult(HttpContext context, AsyncCallback callback)
{
this.context = context;
this.callback = callback;
this.SessionId = context.Request.QueryString["sessionId"].ToString();
}
/// <summary>
/// 向客户端写入信息
/// </summary>
public void Send()
{
this.context.Response.Write(PercentNumber);
}
/// <summary>
/// 完成异步处理,结束请求
/// </summary>
public void DoCompleteTask()
{
if (callback != null)
callback(this);//会触发处理程序中的EndProcessRequest函数,结束请求
this.isComplete = true;
}
#region IAsyncResult 成员

public object AsyncState
{
get { return null; }
}

public System.Threading.WaitHandle AsyncWaitHandle
{
get { return null; }
}

public bool CompletedSynchronously
{
get { return false; }
}

public bool IsCompleted
{
get { return isComplete; }
}

#endregion

}
}
...全文
172 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
Vodka_Lee 2017-04-26
  • 打赏
  • 举报
回复
求楼主解决方法,谢谢咯
peachesTao 2016-04-19
  • 打赏
  • 举报
回复
问题已经解决。还得靠自己!

62,046

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧