2012-10-04 4 views
3

웹 API를 통해 파일을 업로드하는 방법을 만들기 위해 Web API를 사용하고 있습니다. 이 작업을 수행하는 방법에 대한 여러 블로그 게시물을 발견했으며 코드는 모두 Request.Content.ReadAsMultipartAsync() 호출의 주요 공통점과 매우 유사합니다. 내가 가진 문제는 첫 번째 업로드가 정상적으로 작동하지만 IIS가 후속 업로드가 실패하는 오류 상태가되는 것입니다. 처음 32Kb가 들어 오지만 종료됩니다. 디버깅은 ASP.NET 프레임 워크의 어딘가에서 발생하는 null 참조 예외 만 보여줍니다. 여기 웹 API를 통한 파일 업로드가 두 번째 업로드시 실패합니다.

<!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> 

위의 코드는 기본에서 다운로드 할 수 있습니다 ... 내가 가지고있는 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")); 
     } 
    } 
} 

, 나는 여기에서 게시하고있는 페이지입니다 WebApi 솔루션은 https://github.com/JohnLivermore/FileUploadTest입니다. 실행하여 http://localhost:{port}/FormPost.html으로 이동하십시오. 첫 번째 업로드가 성공하지만 (App_Data로 업로드) 이후의 업로드는 첫 번째 32KB 만 업로드 한 다음 실패합니다.

+0

이 코드는 .NET 4 또는 .NET 4.5에서 실행됩니까? – tugberk

답변

5

당신은 무효 방법을 사용하지 말아야합니다 (감사/비동기의 사용 비동기 작업의 동기화는 프레임 워크에 의해 처리됩니다 기다린다).

공허와 비동기가 여러 가지 이유로 잘 작동하지 않습니다.

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")); 
    } 
+1

두 답은 모두 맞지만이 상황은 제 상황에 약간 더 적절합니다. –

+0

동일 함! 이 하나가 완벽하게 작동합니다! – mikemike396

5

코드의 주요 문제는 모든 비동기 작업이 완료 될 때까지 기다리지 않고 메서드를 종료하는 것입니다.

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 프로토콜을 깨는 것을 알고 있어야한다 : 당신은 그 목적을 위해 .Wait()를 사용할 수 있습니다. 귀하의 방법은 더 같이해야한다 :

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

+1

당신의 솔루션은 제게 많은 도움을주었습니다 ... 질문은 제게 물어 보지는 않았지만 매우 도움이되었습니다 ... 감사합니다 –

관련 문제