0

I've encountered many situations while making a library where I wanted to make an asynchronous method synchronous. I usually do something like this:

async Task<object> DoSomethingAsync() { ... } // Original method

object DoSomethingSync()
{ 
    return DoSomethingAsync().Result;
}

This works fine in most cases, but Imagine the body of the async method looking something like this:

async Task<object> DoSomethingAsync()
{
    object result = await CallAServiceAsync().ConfigureAwait(true); // This is important
    // Do something with the result on the caller's context (e.g. UI updates)
    return result;
}

The thread is going to run, return to the caller, do the equivalent of a .Wait() on the Task (in .Result). When CallAServiceAsync() will return, it's going to try to get the original context back, but will deadlock because of the .Result that's waiting.

I could use Task.Run(()=>DoSomethingAsync()).Result, but I feel like there should be a simpler/better way of doing it. I don't believe I need to run the code on another thread each time.

Philippe Paré
  • 4,279
  • 5
  • 36
  • 56
  • 3
    you need to read this https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html – vendettamit May 10 '17 at 19:32
  • 2
    Not a duplicate. That post is 6 years old. Are you telling me people haven't learned over those 6 years and there isn't a more relevant, pulling on more recent ideas, answer? – Mardoxx May 10 '17 at 19:55
  • My answer would be to duplicate the code in your libraries and have both sync and async methods. Or just do away with letting people try and use your libraries in a non async manner – Mardoxx May 10 '17 at 19:59
  • @Mardoxx that's exactly what I'm trying to avoid, not all methods are simple! – Philippe Paré May 10 '17 at 20:21
  • @Gusman you're right, but I'll have to add that I need the return value from `RunSynchronously()`. I could probably create an extension method, but perhaps there's already a way to get the result? – Philippe Paré May 10 '17 at 20:25
  • _"I feel like there should be a simpler/better way of doing it"_ -- a simpler/better way of doing _what_? Calling `ConfigureAwait(true)` is IMHO silly. I don't even know why they gave that method a parameter; there should just be `ConfigureAwaitNoContext()` or something. I can't imagine a real-world scenario where it makes sense to call that method with `true` as the argument value. At the very least, if you are going to ask Stack Overflow how to do something silly like that in a _"simpler/better"_ way, you need to provide a good [mcve] that shows clearly why you think that's a good idea. – Peter Duniho May 10 '17 at 20:26
  • IMHO, if your API is inherently asynchronous, it is better to only expose that and let the caller decide when and how to use it synchronously. If you _must_ provide a synchronous API, then just don't call `ConfigureAwait(true)`. In fact, recommended practice for libraries is to explicitly call `ConfigureAwait(false)`, both for performance reasons and to ensure against accidently getting into exactly the deadlock you're asking about here. If you must provide a synchronous API and you _must_ call `ConfigureAwait(true)` (but _why?_), then see marked duplicate for work-around. – Peter Duniho May 10 '17 at 20:33
  • @PeterDuniho How about a UI library? If I need to do more than one thing asynchronously but update UI in between... `ConfigureAwait(true)` is there for a reason. Because you can't find a reason to use it, doesn't mean it's not useful to others. – Philippe Paré May 10 '17 at 20:42
  • A UI library shouldn't have called `ConfigureAwait(false)` in the first place, and shouldn't be trying to mix asynchronous operations with synchronous. Until you provide an actual [mcve] that would make sense in a real-world scenario, I'm sticking with my assertion that the premise of calling `ConfigureAwait(true)` in your library is flawed. – Peter Duniho May 10 '17 at 20:57
  • 1
    @Mardoxx: The linked answer is extremely dangerous and does not contain proper warnings. For an overview of various approaches (with full disclosure of pros and cons), see [my article on Brownfield Async](https://msdn.microsoft.com/en-us/magazine/mt238404.aspx). – Stephen Cleary May 11 '17 at 20:40

0 Answers0