3

Web API を使用して、Web API 経由でファイルをアップロードする方法を作成しています。これを実現する方法に関するいくつかのブログ投稿を見つけました。コードはすべて非常に似ており、主要な共通点は Request.Content.ReadAsMultipartAsync() 呼び出しです。私が抱えている問題は、最初のアップロードは正常に機能しますが、IIS が障害状態になり、後続のアップロードが失敗することです。最初の 32Kb が入りますが、その後終了します。デバッグでは、ASP.NET フレームワークのどこかで発生する null 参照例外のみが表示されます。

これが私が持っているApiController定義です...

public class FileUploadController : ApiController
{
    public void Post()
    {
        if (Request.Content.IsMimeMultipartContent())
        {
            var path = HttpContext.Current.Server.MapPath("~/App_Data");
            var provider = new MultipartFormDataStreamProvider(path);
            var task = Request.Content.ReadAsMultipartAsync(provider);
            task.ContinueWith(t =>
            {
                if (t.IsFaulted || t.IsCanceled)
                    throw new HttpResponseException(HttpStatusCode.InternalServerError);
            });
        }
        else
        {
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
        }
    }
}

また、ここに私が投稿しているページがあります...

<!doctype html>
<head>
    <title>File Upload Progress Demo #3</title>
</head>
<body>
    <h1>File Upload Progress Demo #3</h1>
    <code>&lt;input type="file" name="myfile[]"></code><br>
    <form action="/api/fileupload" method="post" enctype="multipart/form-data">
    <input type="file" name="myfile"><br>
    <input type="submit" value="Upload File to Server">
    </form>

    <div class="progress">
        <div class="bar"></div>
        <div class="percent">0%</div>
    </div>

    <div id="status"></div>
</body>

上記のコードは、デフォルトの WebApi ソリューションでhttps://github.com/JohnLivermore/FileUploadTestからダウンロードできます。を実行して に移動しhttp://localhost:{port}/FormPost.htmlます。最初のアップロード (App_Data へのアップロード) は成​​功しますが、その後のアップロードでは最初の 32 Kb しかアップロードされず、失敗します。

4

2 に答える 2

5

コードの主な問題は、すべての非同期タスクが終了するのを待たずにメソッドを終了することです。あなたは.Wait()その目的のために使うことができます:

public class FileUploadController : ApiController
{
    public void Post()
    {
        if (Request.Content.IsMimeMultipartContent())
        {
            var path = HttpContext.Current.Server.MapPath("~/App_Data");
            var provider = new MultipartFormDataStreamProvider(path);
            var readAsMultipartTask = Request.Content.ReadAsMultipartAsync(provider);
            var continueWithTask = readAsMultipartTask.ContinueWith(t =>
            {
                if (t.IsFaulted || t.IsCanceled)
                throw new HttpResponseException(HttpStatusCode.InternalServerError);
            });
            continueWithTask.Wait();
        }
        else
        {
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
        }
    }
}

これによりアップロードは正しく機能しますが、適切なアップロードの場合は応答を返さないため、メソッドがHTTPプロトコルを破っていることに注意する必要があります。メソッドは次のようになります。

public class FileUploadController : ApiController
{
    public async Task<HttpResponseMessage> Post()
    {
        if (Request.Content.IsMimeMultipartContent())
        {
            var path = HttpContext.Current.Server.MapPath("~/App_Data");
            var provider = new MultipartFormDataStreamProvider(path);
            await Request.Content.ReadAsMultipartAsync(provider).ContinueWith(t =>
            {
                if (t.IsFaulted || t.IsCanceled)
                    throw new HttpResponseException(HttpStatusCode.InternalServerError);
            });
            //Here you should return a meaningful response
            return Request.CreateResponse(HttpStatusCode.OK); 
        }
        else
        {
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
        }
    }
}

(async / awaitの使用のおかげで、非同期タスクの同期はフレームワークによって処理されます)

于 2012-10-12T20:08:32.757 に答える
5

void メソッドは使用しないでください。

Void と async は、いくつかの理由でうまく連携できません。

   public Task<HttpResponseMessage> Post()
   {
      var rootUrl = "c:/uploads";

      if (Request.Content.IsMimeMultipartContent())
      {
         var streamProvider = new MultipartFormDataStreamProvider(rootUrl);
         var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith<HttpResponseMessage>(t =>
         {
            if (t.IsFaulted || t.IsCanceled)
               throw new HttpResponseException(HttpStatusCode.InternalServerError);

            //do stuff with files if you wish

            return new HttpResponseMessage(HttpStatusCode.OK);
         });
      return task;
      }

      throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
   }
于 2012-10-16T20:36:27.433 に答える