Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

best way to use the nice .net 4.5 HttpClient synchronously

I like the new System.Net.Http.HttpClient class. It has a nice simple API, it doesn't throw on normal errors. But its async only.

I need code that goes (deep inside a server)

foo();
bar();
// compute stuff
var x = GetThingFromOtherServerViaHttp();
// compute more stuff
wiz(x);

classic sequential synchronous code. I saw several SO question that were similar but never actually ended up saying 'do this'. I looked at

client.PostAsync.Wait()

the world screams 'dont do this'. How about:

client.PostAsync.Result()

isnt this just Wait in disguise?

In the end I ended up passing in a lambda callback that processed the result and then awoke the calling thread that was explicitly waiting on a EventWaitHandle. A lot of plumbing. Is there something a little simpler or shoul I just go back to using the old http clients

EDIT:After further reading I suspect that this code has the same issues as Wait and Result, its just a more longwinded deadlock

EDIT: I had MS PM confirm to me recently that there is a mandate 'any API that might take > X ms (I forgot X) must be async', many PMs interpret this as 'async only' (not clear if this is what is intended). Hence the Document DB api being only async.

like image 381
pm100 Avatar asked Aug 12 '15 00:08

pm100


People also ask

How do you call HttpClient synchronously?

Try the following: var task = Task. Run(() => myHttpClient. GetAsync(someUrl)); task.

Is HttpClient an asynchronous?

HttpClient.SendAsync Method (System.Net.Http)Send an HTTP request as an asynchronous operation.

What is difference between HttpClient and WebClient?

In a nutshell, WebRequest—in its HTTP-specific implementation, HttpWebRequest—represents the original way to consume HTTP requests in . NET Framework. WebClient provides a simple but limited wrapper around HttpWebRequest. And HttpClient is the new and improved way of doing HTTP requests and posts, having arrived with .

Is .NET HttpClient thread-safe?

HttpClient is a very important class in the . NET/. NET Core ecosystem. HttpClient is designed as a shared instance that is also a thread-safe if used properly.


2 Answers

From http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx:

return Task.Run(() => Client.PostAsync()).Result;
like image 144
Jeff Dunlop Avatar answered Oct 13 '22 12:10

Jeff Dunlop


@Noseratio - of course I am concerned about deadlocks :-)

You only would be concerned about deadlocks if you're on a thread with synchronization context.

That would normally be either the main thread of a UI application (client-side), or random ASP.NET thread processing an HTTP request (server-side). In either case you really shouldn't be blocking it.

The accepted answer might help mitigating the deadlock, but blocking like this would still hurt the end user experience of your UI app (the UI would be frozen), or the server-side app scalability (a thread wasted with blocking, while it could be serving another request). Just don't block and use async/await all the way through.

You mentioned "deep inside a server" but provided no details on what kind of server-side app is that. Most of the modern server-side frameworks have a good plumbing for async/await, so it shouldn't be a problem embracing it.

Updated to address the comment:

I still dont like the fact that the same code written in different places will deadlock. I would expect the wait call in a deadlock-prone environment to throw

This is not particularly a problem of async/await but is that of synchronization context concept in general, when it's used with blocking code. Here is the deadlock in a nutshell:

private void Form1_Load(object sender, EventArgs e)
{
    var mre = new System.Threading.ManualResetEvent(initialState: false);
    System.Threading.SynchronizationContext.Current.Post(_ => 
        mre.Set(), null);
    mre.WaitOne();
    MessageBox.Show("We never get here");
}

In theory, it might be possible to try to mitigate potential deadlocks inside SynchronizationContext.Post, say by checking Thread.ThreadState == System.Threading.ThreadState.WaitSleepJoin. That would not however be a 100% reliable solution.

like image 30
noseratio Avatar answered Oct 13 '22 13:10

noseratio