Asp.net

使用 ASP.Net Web API 的多部分錶單 POST

  • March 9, 2016

我有一個 POST ASP.Net Web Api 方法,改編自A guide to asynchronous file uploads in ASP.NET Web API RTM

我遇到了第一個請求被觸發並完成後觸發的所有請求的錯誤任務問題。

場景如下:我有一個範例頁面,該頁面將文件連同其他參數一起發佈到 Web API Post 方法。第一次執行良好,文件已上傳。但是,所有後續請求最終都會使任務處於故障狀態。我收到“MIME 多部分流意外結束。MIME 多部分消息不完整。” 任何想法為什麼?

下面粘貼的是我的 Post 方法、範例 html 表單和聚合異常的原始碼。

   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;
   }

我正在使用這樣的範例表單觸發這個 web api:

<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());

           });

但是,這是非常喜怒無常的程式碼。它有時有效,但有時無效。換句話說,它並不能完全解決問題。

事實證明,正如 Filip 在評論中所建議的那樣,我改編自實現消息處理程序以跟踪您的 ASP .net Web API 使用情況的 Web API 使用處理程序正在讀取內容正文,因此在請求正在我的 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);
  });

請求將被緩衝,並且可以讀取兩次,因此可以在管道中進一步上傳。希望這可以幫助。

引用自:https://stackoverflow.com/questions/12384544