2016-03-17 5 views
1

Мне просто интересно, может ли кто-нибудь объяснить, что здесь происходит.WebAPI HttpContext Null Inside ContinueWith() => tast

Учитывая этот метод Post на контроллере API:

public HttpResponseMessage PostImage() 
{ 
    var request = HttpContext.Current.Request; 
    var c = SynchronizationContext.Current; 

    var result = new HttpResponseMessage(HttpStatusCode.OK); 
    if (Request.Content.IsMimeMultipartContent()) 
    {    
     Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider()).ContinueWith((task) => 
     { 
      MultipartMemoryStreamProvider provider = task.Result; 
      foreach (HttpContent content in provider.Contents) 
      { 
       Stream stream = content.ReadAsStreamAsync().Result; 
       Image image = Image.FromStream(stream); 
       var uploadFileName = content.Headers.ContentDisposition.FileName; 

       var requestInside = HttpContext.Current.Request; // this is always null  

       string filePath = Path.Combine(HostingEnvironment.MapPath(ConfigurationManager.AppSettings["UserFilesRootDir"]), userprofile.UserCode); 

       //string[] headerValues = (string[])Request.Headers.GetValues("UniqueId"); 

       string fileName = userprofile.UserCode + ".jpg"; 

       string fullPath = Path.Combine(filePath, fileName); 

       image.Save(fullPath); 
      } 
     }); 
     return result; 
    } 
} 

Почему бы var requestInside = HttpContext.Current.Request; быть нулевым?

Я проверил все соответствующие параметры:

<compilation debug="true" targetFramework="4.5"> 
... 

<httpRuntime targetFramework="4.5" 

И SynchronizationContext.Current более новая AspNetSynchronizationContext, а не LegacyAspNetSynchronizationContext.

Я предполагаю в данный момент, что это потому, что я нахожусь в другом потоке, это правильное предположение?

+0

Мне любопытно. Почему бы не использовать операторы async/wait, чтобы контекст запроса был захвачен при возобновлении выполнения после завершения асинхронного метода? Поэтому отметьте подпись метода 'public async Task PostImage' – Igor

+0

Конечно, я все еще работаю над этим кодом и сделаю это, но просто любопытно. – Jammer

+0

Я обновил свой ответ ссылкой «ContinueWith» и как вы могли бы заставить его работать с этими изменениями. – Igor

ответ

1

ContinueWith не гарантированно работает в одной и той же теме, поэтому контекст синхронизации может быть потерян. Вы можете изменить свой вызов, чтобы указать возобновление в текущем потоке с параметром TaskScheduler.Current. See this previous SO answer.

Если вы используете шаблон await/async, он автоматически фиксирует текущий контекст syncronization при возобновлении после завершения ожидаемой операции. Это делается путем возобновления операции в том же потоке, который связан с этим контекстом. Дополнительным преимуществом, IMHO, является более чистый код.

Вы можете изменить свой код на тот, который использует этот шаблон. Я не делал никаких других изменений, кроме использования async/await.

public async Task<HttpResponseMessage> PostImage() 
{ 
    var request = HttpContext.Current.Request; 
    var c = SynchronizationContext.Current; 

    var result = new HttpResponseMessage(HttpStatusCode.OK); 
    if (Request.Content.IsMimeMultipartContent()) 
    { 
     MultipartMemoryStreamProvider provider = await Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider()); 
     foreach (HttpContent content in provider.Contents) 
     { 
      Stream stream = await content.ReadAsStreamAsync(); 
      Image image = Image.FromStream(stream); 
      var uploadFileName = content.Headers.ContentDisposition.FileName; 

      var requestInside = HttpContext.Current.Request; // this is always null  

      string filePath = Path.Combine(HostingEnvironment.MapPath(ConfigurationManager.AppSettings["UserFilesRootDir"]), userprofile.UserCode); 

      //string[] headerValues = (string[])Request.Headers.GetValues("UniqueId"); 

      string fileName = userprofile.UserCode + ".jpg"; 

      string fullPath = Path.Combine(filePath, fileName); 

      image.Save(fullPath); 
     } 
    } 
    return result; 
} 
+1

Действительно, это имеет смысл, мое первоначальное предположение (на основе ContinueWith) было правильным. Спасибо, Игорь. – Jammer

Смежные вопросы