1

I hope someone has an explanation to this, because it drives me nuts.

I have the following code in a WinForms application to upload a file using HttpClient to a Web API service.

ProgressMessageHandler progressMsgHandler = new ProgressMessageHandler();
progressMsgHandler.HttpSendProgress += (s, e) =>
{
   this.InvokeIfNeeded(() =>
   {
      // LOG
      this.AddLogLine("Progress: " + e.ProgressPercentage.ToString());
    });
};

using (var client = HttpClientFactory.Create(progressMsgHandler))
{ 
   using (var content = new MultipartFormDataContent())
   {
      var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
      var streamContent = new StreamContent(stream);
      content.Add(streamContent);

      var url = String.Format("{0}?src={1}", STR_URL_FILEMGMT, "IM");
      client.PostAsync(new Uri(url), content).ContinueWith(task =>
      {
        if (task.Result.IsSuccessStatusCode)
         {
            this.InvokeIfNeeded(() =>
            {
               // LOG
               this.AddLogLine("File has been uploaded OK!");
            });
         }
         else
            this.InvokeIfNeeded(() =>
            {
               // LOG
               this.AddLogLine(String.Format("Error during upload: '{0}'", task.Exception.Message));
            });                                
      });
   }
}

Please note, entire code listed is also wrapped into a try catch where exception would be printed, if any.

Very weird to me is that I don't get any log line printed at all. Neither for progress, neither for posting with success, neither for posting with errors nor in the global try catch.

During debug, I see the code executing, but doesn't hit any breakpoints where the log lines are.

Probably I don't use correctly HttpClient or these tasks (I am beginner at this btw)? Does anyone know what's going wrong with my code?


UPDATE (after getting the solution from Noseratio):

Extra information which helps me understand that HttpClient does not need to be disposed can be found here

Community
  • 1
  • 1
Learner
  • 3,297
  • 4
  • 37
  • 62

1 Answers1

4

In your code, client.PostAsync returns instantly (while the operation continues in the background). This unwinds both of your using statements, so the HttpClient object gets disposed of before the upload has finished.

If you want to utilize using here, you'd need to use await instead of ContinueWith:

var result = await client.PostAsync(...);
if (result.IsSuccessStatusCode)
{
    // ...
}

If you need to target .NET 4.0 but develop with VS2012+ , you still can use async/await, Microsoft provides the Microsoft.Bcl.Async library for that.

noseratio
  • 59,932
  • 34
  • 208
  • 486
  • This is of great value. Btw, I am using VS2010, so I want to avoid async/await for now. Could you offer me some hints? Thanks a lot! – Learner Mar 06 '14 at 12:55
  • Indeed, this link says the same: http://forums.asp.net/t/1775726.aspx ... I guess I have to find a way to dispose it in a good way now – Learner Mar 06 '14 at 13:32
  • @Cristi,you won't be able to benefit from `using` without `await`, but you can use some handy composition patterns: http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx – noseratio Mar 06 '14 at 20:08
  • Very useful, thanks. For now I removed the using clause, and strangely I got the same behavior. Maybe is because the second using. I have to make more tests.. – Learner Mar 06 '14 at 20:28
  • Yes, it is most likely the othet `using` which destroys the ` content` object. – noseratio Mar 06 '14 at 20:30
  • Yeah, that did it. Though I noticed another trouble: for ~1Gb file it just stuck at ~4%... again without any error... – Learner Mar 06 '14 at 20:41
  • @Cristi, IMO, 1GB is the way to much for a single HTTP upload. You should upload it chunk by chunk and then re-assemble on the server. – noseratio Mar 06 '14 at 20:43
  • I think I should go for HttpWebRequest – Learner Mar 06 '14 at 20:54
  • @Cristi, in my experience `HttpClient` is more robust than `HttpWebRequest`, but I don't think it's a limitation of the client stack. Just imagine what happens if you have a disconnect during a 1GB upload. This could be very frustrating for the user. – noseratio Mar 06 '14 at 20:57
  • 4% from 1Gb. Only after 40Mb it broke (on my local machine). Not sure if I should call this "robust". Anyway... your idea is not bad, but I don't think is applicable for me. I have special files which I want to transfer, cannot see how to handle the process if I split them up. – Learner Mar 06 '14 at 21:03
  • @Cristi, are you using the latest [HTTP Client Libraries 2.2.18](https://www.nuget.org/packages/Microsoft.Net.Http)? Otherwise, it could be some other bug in your logic, I'd strongly be inclined to think so. – noseratio Mar 06 '14 at 21:14
  • just so you know: "This package is not supported in Visual Studio 2010..." - thanks for helping me out. I think your idea of re-assembling on server is very good, it requires a bit more work, but should be feasible. – Learner Mar 06 '14 at 21:17
  • since HttpClient is more for 4.5 and VS2012+ I would stick to the standard HttpWebRequest. I used WebClient earlier, it worked perfect for files up to 1Gb. – Learner Mar 06 '14 at 21:20
  • Indeed I missed that :) You do need to use `HttpWebRequest` with VS2010. `HttpClient` would work for .NET 4.0 with `Microsoft.Bcl.Async`, but VS2012+ would still be required as development environment. – noseratio Mar 06 '14 at 21:22
  • 1
    Thanks a lot for your support, very much appreciated! – Learner Mar 06 '14 at 21:24