What is the best way to use HttpClient
and avoid deadlock? I am using the code below, called entirely from synchronous methods, but I concerned it maybe causing a deadlock.
I've done some reading on functions like .ConfigureAwait(false)
, .GetAwaiter()
, .GetResult()
but I am looking for input on the best practice approach.
Not quite exact code, but close enough.
public static bool TryRequest(string url, out response)
{
HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
using (HttpClient client = new HttpClient())
{
HttpResponseMessage responseMessage = null;
switch (verb)
{
case HttpVerb.Put:
responseMessage = client.PutAsync(url, content).Result;
break;
case HttpVerb.Post:
responseMessage = client.PostAsync(url, content).Result;
break;
case HttpVerb.Delete:
responseMessage = client.DeleteAsync(url).Result;
break;
case HttpVerb.Get:
responseMessage = client.GetAsync(url).Result;
break;
}
if (responseMessage.IsSuccessStatusCode)
{
responseContent = responseMessage.Content.ReadAsStringAsync().Result;
statusCode = responseMessage.StatusCode;
}
}
}
It looks like you are trying to run asynchronous code synchronously.
With WinForms and WPF YOU CANNOT SAFELY DO THIS!
The only thing you can do is to use async all the way up. Its a known problem with .net async. You can use public async void XXX()
methods. But then you don't know when they complete. You should ONLY ever use async void
when coupled with an event handler.
The reason you are getting deadlocks is that the default TaskFactory
will try to marshal interupt callbacks back to the SynchronizationContext
, which is likely your UI thread.
Even if you use Task.ConfigureAwait(false)
there is no guarantee that further down the callstack you don't have a callback which expects the UI thread.
As long as you block the SynchronizationContext
thread, there is a very high possibility that you will deadlock.
It is also worth noting that it is possible that the asynchronous code seems to sometimes work. This is because, an async method that returns a Task
, is allowed to synchronously complete (for example Task.Return<T>(T result)
). This will often happen with methods that have a cache (like HttpRequests).
EDIT: @SriramSakthivel suggest that you can run an async method synchronously by wrapping it within Task.Run
. This is because Task.Run
will run the code without the parent SynchronizationContext
.
Task.Run(RunRequest).Result;
I personally do not recommend this, as it relies on the specific implementation of Task.Run
along with TaskFactory
to work. It is entirely possible (but unlikely) that a new version of .net will break this piece of code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With