4

非同期で、AJAX非同期リクエストを介してファイルの進行状況を更新できるファイルアップロードハンドラーをC#で作成しようとしています。基本的に、リクエストがPOSTの場合、セッションに情報をロードしてからアップロードを開始します。リクエストがGETの場合、アップロードの現在の状態(アップロードされたバイト数、合計バイト数など)を返します。非同期ハンドラーである必要があるかどうかは完全にはわかりませんが、ファイルが非常に大きくなる可能性があるため、これが最適であると思いました。基本非同期ハンドラーには、このMSDN記事のハンドラーと非常によく似たものを使用しました。以下に私のコードのいくつかの重要なセクションを投稿しました。私が抱えている問題は、POSTが完了するまでGET情報を受け取らないことです。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が非同期で実行されていることを確認するなど、さまざまなことを試しましたが、現時点では、問題について別の視点が必要だと思いますので、誰かが提供できる支援に感謝します。

4

1 に答える 1

4

デフォルトのASP.Netセッションマネージャーを使用していると仮定し、セッションを取得するために呼び出していることがわかりGetSessionStoreます。残念ながら、デフォルトのセッションマネージャは、呼び出しにセッションストアへの書き込みアクセスが必要な場合にすべての要求をシリアル化します。このStackOverflowの質問とセッション状態に関するこのMSDNアークルには、セッション状態とそのロック動作に関する非常に役立つ情報がいくつかあります。

ここで、問題を処理するために、MVCコントローラーを使用しているかどうか、またはカスタムIHttpHandlerを作成しているかどうかに応じて、いくつかのことを行う必要があります。

  • 独自のIHttpHandlerを作成している場合は、ハンドラーにまたはインターフェイスが追加されていないことを確認してください。そうすることで、パイプラインはセッションの検索をスキップし、直接処理に進みます。この状況ではnullになります。IRequiresSessionStateIReadOnlySessionStatecontext.Session
  • MVCを使用してリクエストを処理している場合は、のSessionStateBehaviorを渡すSessionState属性でコントローラークラスを装飾する必要があります。SessionStateBehavior.Disabled

いずれの場合も、アップロードステータスを保存するためにSessionオブジェクトに依存することはできません。SessionIDからキー設定された静的ConcurrentDictionaryを作成し(アップロードクエリ文字列を渡すか、Cookieを自分で読み取る必要があります。Session.SessionIdを呼び出すと、再度ブロックされます)、アップロードステータスをそこに保存できます(それらも同時*であるように見えます)。

別のオプションは、SessionStateProviderを独自のカスタムプロバイダーに置き換えることですが、この状況ではやり過ぎかもしれません。

于 2012-10-26T14:46:36.617 に答える