I’m using the HttpClient to post data to a remote service in a .NET 4.0 project. I’m not concerned with this operation blocking, so I figured I could skip ContinueWith or async/await and use Result.
While debugging, I ran into an issue where the remote server wasn’t responsive. As I stepped through the code, it seemed like my code just stopped running on the third line… the current stack pointer line stopped being highlighted yellow, and didn’t advance to the next line. It just disappeared. It took me a while to realize that I should wait for the request to timeout.
var client = new HttpClient();
var task = client.PostAsync("http://someservice/", someContent);
var response = task.Result;
My understanding was that calling Result on the Task caused the code to execute synchronously, to behave more like this (I know there is no Post method in the HttpClient):
var client = new HttpClient();
var response = client.Post("http://someservice/", someContent);
I’m not sure this is a bad thing, I’m just trying to get my head around it. Is it really true that by virtue of the fact that the HttpClient is returning Tasks instead of the results directly, my application is automatically taking advantage of asynchrony even when I think I’m avoiding it?
In Windows, all I/O is asynchronous. Synchronous APIs are just a convenient abstraction.
So, when you use
HttpWebRequest.GetResponse, what actually happens is the I/O is started (asynchronously), and the calling thread (synchronously) blocks, waiting for it to complete.Similarly, when you use
HttpClient.PostAsync(..).Result, the I/O is started (asynchronously), and the calling thread (synchronously) blocks, waiting for it to complete.I usually recommend people use
awaitrather thanTask.ResultorTask.Waitfor the following reasons:Taskthat is the result of anasyncmethod, you can easily get into a deadlock situation.Task.ResultandTask.Waitwrap any exceptions in anAggregateException(because those APIs are holdovers from the TPL). So error handling is more complex.However, if you’re aware of these limitations, there are some situations where blocking on a
Taskcan be useful (e.g., in a Console application’sMain).