9

AガイドからASP.NETWebAPIRTMでの非同期ファイルアップロードに適合したPOSTASP.NetWebApiメソッドがあります。

最初のリクエストが実行されて完了した後にすべてのリクエストが実行されるという、障害のあるタスクの問題が発生しています。

シナリオは次のとおりです。ファイルを他のパラメーターとともにWebAPIPostメソッドにPOSTするサンプルページがあります。初めて正常に動作し、ファイルがアップロードされます。ただし、後続のすべての要求は、タスクを障害状態で終了します。「MIMEマルチパートストリームの予期しない終了が発生します。MIMEマルチパートメッセージは完全ではありません。」なぜ何かアイデアはありますか?

以下に貼り付けたのは、Postメソッドのソースコード、サンプルhtmlフォーム、およびAggregateExceptionです。

    public Task<HttpResponseMessage> Post([FromUri]string memberNumber)
    {
        // Check if the request contains multipart/form-data.
        if (!Request.Content.IsMimeMultipartContent())
        {
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
        }

        string root = HttpContext.Current.Server.MapPath("~/App_Data");
        var provider = new MultipartFormDataStreamProvider(root);

        // Read the form data and return an async task.
        var task = Request.Content.ReadAsMultipartAsync(provider).
            ContinueWith(t =>
            {
                if (t.IsFaulted || t.IsCanceled)
                {
                    throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception));
                }

                return Request.CreateResponse(HttpStatusCode.OK, new MyModel());
            });

        return task;
    }

次のようなサンプルフォームを使用して、このWebAPIを起動しています。

<form name="form1" method="post" enctype="multipart/form-data" action="api/claims/asd123" style="margin:auto;width:500px;">
    <div>
        <label for="HCPracticeNumber">HC Pratice Number:</label>
        <input type="text" name="HCPracticeNumber" id="HCPracticeNumber"/>
    </div>
    <div>
        <label for="ServiceDate">Service/Treatment date:</label>
        <input type="text" name="ServiceDate" id="ServiceDate"/>
    </div>
    <div>
        <label for="AmountClaimed">Amount Claimed:</label>
        <input type="text" name="AmountClaimed" id="AmountClaimed"/>
    </div>
    <div>
        <label for="Image">Image Attachment:</label>
        <input name="Image" type="file" />
    </div>
    <div>
        <input type="submit" value="Submit" />
    </div>
</form>

返されるAggregateExceptionは次のとおりです。

<Error>
<Message>An error has occurred.</Message>
    <ExceptionMessage>One or more errors occurred.</ExceptionMessage>
    <ExceptionType>System.AggregateException</ExceptionType>
    <StackTrace/>
    <InnerException>
        <Message>An error has occurred.</Message>
        <ExceptionMessage>
            Unexpected end of MIME multipart stream. MIME multipart message is not complete.
        </ExceptionMessage>
        <ExceptionType>System.IO.IOException</ExceptionType>
        <StackTrace>
            at System.Net.Http.Formatting.Parsers.MimeMultipartBodyPartParser.<ParseBuffer>d__0.MoveNext() at System.Net.Http.HttpContentMultipartExtensions.MoveNextPart(MultipartAsyncContext context)
        </StackTrace>
    </InnerException>
</Error>

アップデート:

彼のブログサイトでのFilipの提案の後、私はpostメソッドを変更して、次のようにストリーム位置を0にリセットしました。

        Stream reqStream = Request.Content.ReadAsStreamAsync().Result;
        if (reqStream.CanSeek)
        {
            reqStream.Position = 0;
        }
        var task = Request.Content.ReadAsMultipartAsync(provider).
            ContinueWith(t =>
            {
                if (t.IsFaulted || t.IsCanceled)
                {
                    throw new HttpResponseException(
                    Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
                    t.Exception));
                }

                return Request.CreateResponse(HttpStatusCode.OK, new MyModel());

            });

しかし、これは非常に気質のあるコードです。動作する場合と動作しない場合があります。つまり、問題を完全に解決するわけではありません。

4

2 に答える 2

15

コメントでFilipが示唆しているように、メッセージハンドラーの実装からASP .net Web APIの使用状況を追跡するために適応させたWebAPIの使用状況ハンドラーは、コンテンツ本文を読み取っていたため、ストリーム上の位置シーカーをいじっていたことがわかりました。リクエストはPOSTメソッドで処理されていました。

そこで、リクエストがIsMimeMultipartContentタイプの場合にリクエストの本文を読み取らないように、WebApiUsageHandlerに条件ステートメントを追加しました。これで問題が修正されました。

アップデート

回答を別のオプションで更新したいのですが、Filipからメールで提案されたので、次のように文書化されます。

本文を読み取る直前に、API使用ハンドラー内でこのコードを使用する場合:

   //read content into a buffer
   request.Content.LoadIntoBufferAsync().Wait();

   request.Content.ReadAsStringAsync().ContinueWith(t =>
   {
       apiRequest.Content = t.Result;
       _repo.Add(apiRequest);
   });

リクエストはバッファリングされ、2回読み取ることができるため、パイプラインのさらに下流でアップロードが可能になります。お役に立てれば。

于 2012-09-12T12:15:25.187 に答える
2

これは、元の投稿者の質問に対する答えではありません。ただし、コードでReadAsMultipartAsync()メソッドを複数回呼び出すと、同じ例外が発生しました。

public async Task<IHttpActionResult> PostFiles()
{

     // Check if the request contains multipart/form-data.
     if (!Request.Content.IsMimeMultipartContent())
     {
         return Content(HttpStatusCode.BadRequest, "Unsupported media type. ";
    }
     try
     {
        var provider = new CustomMultipartFormDataStreamProvider(workingFolder);

        await Request.Content.ReadAsMultipartAsync(provider); // OK
        await Request.Content.ReadAsMultipartAsync(provider); // calling it the second time causes runtime exception "Unexpected end of MIME multipart stream. MIME multipart message is not complete"
        ... 

    }
    catch(Exception ex)
    {
        ...
    }
}
于 2016-03-09T15:03:08.333 に答える