9

A guide to asynchronous file uploads in ASP.NET Web API RTM에서 수정 된 POST ASP.Net Web API 메서드가 있습니다.ASP.Net 웹 API를 사용하는 Multipart form POST

첫 번째 요청이 실행되고 완료된 후에 시작된 모든 요청에 ​​대해 오류가 발생한 작업 문제가 발생했습니다.

다음은 시나리오입니다. 다른 매개 변수와 함께 파일을 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; 
    } 

나는이 같은 샘플 양식을 사용하여이 웹 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> 

업데이트 :

필립의 블로그 사이트에서 필자의 제안을받은 후, 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()); 

      }); 

그러나 이것은 매우 까다로운 코드입니다. 때로는 다른 때가 아닙니다. 즉, 문제를 완전히 해결하지 못합니다.

+0

요청 본문을 다른 곳에서 읽으십니까? 즉 메시지 처리기? 양식의 다른 변수로 무엇을합니까? 일반적으로 이러한 오류는 요청 본문이 이미 한 번 읽었으며 콘텐츠 스트림 위치가 끝에 있음을 의미합니다. –

+0

또한 웹 API RTM을 사용하고 있습니까? –

+0

예, 웹 API RTM을 사용하고 있습니다. 예, HTTP-Method-Override Header를 확인하기위한 하나의 메시지 처리기가 있고 WebApiUsage Handler와 다른 인증 처리기가 있습니다. 나는 다른 매개 변수들을 가지고 아직 아무것도하고 있지 않다. 그러나 그것들을 또한 읽을 것이다. 먼저이 문제를 해결하기 전에 문제를 해결하고 싶습니다. 읽을 수없는 다른 매개 변수가이 문제와 관련이 있습니까? – badikumar

답변

14

Filip이 의견에서 제안한 것처럼 Implementing Message Handlers To Track Your ASP .net Web API Usage에서 수정 한 웹 API 사용 핸들러가 내용 본문을 읽고 있으므로 요청이 POST에서 처리 될 때 스트림의 위치 탐색기가 엉망이었습니다 방법.

그래서 요청이 IsMimeMultipartContent 유형 인 경우 요청 본문을 읽지 않기 위해 WebApiUsageHandler에 조건문을 추가했습니다. 이 문제가 해결되었습니다.

업데이트

나는 다른 옵션에 대한 답을 업데이트 할이 기록되도록 이메일을 통해 필립 나에게 제안 :

당신은 API 사용 핸들러 내부에서이 코드를 사용하는 경우, 단지 몸을 읽기 전에 :

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

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

요청을 버퍼링 할 두 번 읽을 수있을 것입니다, 따라서 업로드는 파이프 라인 아래로 더 가능합니다. 희망이 도움이됩니다.

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) 
    { 
     ... 
    } 
} 
관련 문제