c# - ASP.Net 异步 HTTP 文件上传处理程序

标签 c# javascript asp.net asynchronous httphandler

我正在尝试在 C# 中创建一个异步的文件上传处理程序,并且可以通过 AJAX 异步请求提供有关文件进度的更新。基本上,如果请求是 POST,它会将一些信息加载到 session 中,然后开始上传,如果请求是 GET,它会返回上传的当前状态(上传的字节数、总字节数等)。我不完全确定它需要是一个异步处理程序,但文件可能非常大,所以我认为这样效果最好。对于基本异步处理程序,我使用了与此 MSDN article 中的处理程序非常相似的东西。 .我在下面发布了我的代码的一些关键部分。我遇到的问题是在 POST 完成之前我没有收到任何 GET 信息。我会提到在这个例子中我使用的是 jQuery对于 GET 请求和 BlueImp用于发布文件。

HTML 和 JavaScript

<input id="somefile" type="file" />

$(function () {
  name = 'MyUniqueId130';
  var int = null;
  $('#somefile').fileupload({
    url: '/fileupload.axd?key='+name,
    done: function (e, data) { clearInterval(int); }
  });

  $('#somefile').ajaxStart(function(){
    int = setInterval(function(){
    $.ajax({
      url: '/fileupload.axd?key='+name,
      dataType: 'json',
      async: true
    })
    .done(function(e1, data1){
      if(!e1.InProgress || e1.Complete || e1.Canceled)
        clearInterval(int);
    });
  }, 10000)});
});

异步处理请求方法只是调用正确的方法,无论是 POST 还是 GET 到以下方法之一,然后调用 CompleteRequest 来结束请求:

private static void GetFilesStatuses(HttpContext context)
{
  string key = context.Request.QueryString["key"];
  //A dictionary of <string, UploadStatus> in the session
  var Statuses = GetSessionStore(context);
  UploadStatus ups;

  if (!String.IsNullOrWhiteSpace(key))
  {
    if (Statuses.TryGetValue(key, out ups))
    {
      context.Response.StatusCode = (int)HttpStatusCode.OK;
      context.Response.Write(CreateJson(ups));
    }
    else
    {
      context.Response.StatusCode = (int)HttpStatusCode.NotFound;
    }
  }
  else
  {
    context.Response.StatusCode = (int)HttpStatusCode.OK;
    context.Response.Write(CreateJson(Statuses.Values));
  }
}

private static void UploadFile(HttpContext context)
{
 var Statuses = GetSessionStore(context);
 string key = context.Request.QueryString["key"];

 if (String.IsNullOrWhiteSpace(key))
 {
   context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
   return;
 }

 HttpPostedFile file = context.Request.Files[0];
 string extn = file.FileName.LastIndexOf('.') == -1 ? "" :
    file.FileName.Substring(file.FileName.LastIndexOf('.'), (file.FileName.Length - file.FileName.LastIndexOf('.')));
 string temp = GetTempFileName(path, extn);
 UploadStatus status = new UploadStatus()
 {
   FileName = file.FileName,
   TempFileName = temp,
   Path = path,
   Complete = false,
   Canceled = false,
   InProgress = false,
   Success = true,
   BytesLoaded = 0,
   TotalBytes = file.ContentLength
 };
 Statuses.Add(key, status);
 byte[] buffer = new byte[bufferSize];
 int byteCount = 0;

 using (var fStream = System.IO.File.OpenWrite(context.Request.MapPath(path + temp)))
 {
   uploads.Add(status);

   while ((byteCount = file.InputStream.Read(buffer, 0, bufferSize)) > 0 && !status.Canceled)
   {
     status.InProgress = true;
     status.BytesLoaded += byteCount;
     fStream.Write(buffer, 0, byteCount);
   }

   status.Complete = !status.Canceled;
   status.InProgress = false;
   status.Success = true;

   if (status.Canceled)
   {
     Statuses.Remove(temp);
   }

   context.Response.StatusCode = (int)HttpStatusCode.OK;
 }
}

我已经尝试了很多东西,例如非异步处理程序、异步处理程序,以确保 JavaScript 异步运行,但在这一点上我认为我需要对这个问题有不同的看法,所以感谢您提供的任何帮助.

最佳答案

我假设您使用的是默认的 ASP.Net session 管理器,并且我看到您调用了 GetSessionStore 来获取您的 session 。不幸的是,当调用需要对 session 存储的写访问权限时,默认 session 管理器会序列化所有请求。这StackOverflow question还有这个MSDN arcle on Session State有一些关于 session 状态及其锁定行为的非常有用的信息。

现在,为了解决您的问题,您将不得不做一些事情,这取决于您是使用 MVC Controller 还是编写自定义 IHttpHandler。

  • 如果您正在编写自己的 IHttpHandler,请确保您没有IRequiresSessionStateIReadOnlySessionState 接口(interface)添加到您的处理程序。这样做时,管道将跳过寻找 session 并直接进行处理。 context.Session 在这种情况下将为空。
  • 如果您使用 MVC 来处理请求,则需要使用 SessionState attribute 装饰您的 Controller 类传入 SessionStateBehavior SessionStateBehavior.Disabled 的。

在任何一种情况下,您都无法依赖 Session 对象来存储您的上传状态。您可以创建一个静态的 ConcurrentDictionary 从他们的 SessionID 键控(您需要传入上传查询字符串或自己读取 cookie,调用 Session.SessionId 只会再次阻止您)并将您的上传状态存储在那里(这看起来它们也是并发的*)。

另一种选择是将 SessionStateProvider 替换为您自己的自定义提供程序,但在这种情况下这可能有点矫枉过正。

关于c# - ASP.Net 异步 HTTP 文件上传处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13088753/

相关文章:

c# - 更改所有管理员壁纸

c# - 使用 Entity Framework 在 View 上创建伪外键

javascript - 在 <td> 中生成动态表

asp.net - 如何在用户控件上实现 TabIndex

asp.net - Visual Studio 如何决定在哪个端口上运行应用程序?

c# - Array、ArrayList 和 List 之间有什么区别?

c# - 使用 Google 和 ASP.NET Core Identity 进行无限登录重定向循环

javascript - 我可以用 jQuery 重新加载多个 div 吗?

javascript - 如何将函数从工厂传递到 Controller angularJS

c# - 输入字符串的格式不正确,即使我有正确的值