2013-05-29 41 views
1

我有一个WebApi的异步文件上传功能的问题。MultipartFormDataStreamProvider并保留当前的HttpContext

目前我能够使用提供者保存文件,但是我希望使用服务(_myService)来记录上传文件的文件名。在服务内部,它使用另一个服务来获取当前的UserId。它通过使用当前的HttpContext来完成。不幸的是,当前的HttpContext似乎在新的任务线程中丢失了。

我试着添加TaskScheduler.FromCurrentSynchronizationContext()作为任务的第二个参数,但是这没有效果。不太清楚这给了我什么。所以我需要一些将Http上下文传递到新线程的方法。我将如何实现这一目标?

[ValidationFilter] 
     public Task<FileUpModel> Upload([FromUri]int ReportType, [FromUri]string LocationDescription, string AdditionalInformation) 
     { 
      if (Request.Content.IsMimeMultipartContent()) 
      { 
       var imagePath = HttpContext.Current.Server.MapPath("~/App_Data"); 

       var provider = new MyFormDataStreamProvider(imagePath); 

       var task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(
       t => 
       { 

        if (t.IsFaulted || t.IsCanceled) 
         throw new HttpResponseException(HttpStatusCode.InternalServerError); 

        var fileInfo = provider.FileData.FirstOrDefault(); 
        if (fileInfo == null) 
         throw new HttpResponseException(HttpStatusCode.InternalServerError); 

        // httpContext is lost here... 
        _myService.LogUploadedFile(fileInfo.LocalFileName); 

        var uploadModel = new FileUpModel { success = true }; 
        return uploadModel; 
       }, TaskScheduler.FromCurrentSynchronizationContext()); 

       return task; 
      } 
      else 
      { 
       throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted")); 
      }    
     } 

回答

3

我最终发现了一个工作,它看起来并不像我所希望的那样干净。基本上,我将上下文的副本保存在一个单独的变量中,并将其传递给闭包。不知道这是否是最佳做法,但它的工作原理!

var currentHttpContext = HttpContext.Current; 

     var task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(
     t => 
     { 
      // Enquiry service requires access to authentication data which is retrieved via http context. 
      // Not ideal but set the http context here so it available on the new thread.      
      HttpContext.Current = currentHttpContext; 

      if (t.IsFaulted || t.IsCanceled) 
       throw new HttpResponseException(HttpStatusCode.InternalServerError); 

      var fileInfo = provider.FileData.FirstOrDefault(); 
      if (fileInfo == null) 
       throw new HttpResponseException(HttpStatusCode.InternalServerError); 

      _myService.LogUploadedFile(fileInfo.LocalFileName); 

      var uploadModel = new FileUpModel { success = true }; 
      return uploadModel; 
     }); 

     return task;