I have a public async Task Foo()
method that I want to call from a synchronous method. So far all I have seen from MSDN documentation is calling async
methods via async
methods, but my whole program is not built with async
methods.
Is this even possible?
Here's one example of calling these methods from an asynchronous method:
Walkthrough: Accessing the Web by Using Async and Await (C# and Visual Basic)
Now I'm looking into calling these async
methods from synchronous methods.
Best Answer
Asynchronous programming does "grow" through the code base. It has been compared to a zombie virus. The best solution is to allow it to grow, but sometimes that's not possible.
I have written a few types in my Nito.AsyncEx library for dealing with a partially-asynchronous code base. There's no solution that works in every situation, though.
Solution A
If you have a simple asynchronous method that doesn't need to synchronize back to its context, then you can use
Task.WaitAndUnwrapException
:You do not want to use
Task.Wait
orTask.Result
because they wrap exceptions inAggregateException
.This solution is only appropriate if
MyAsyncMethod
does not synchronize back to its context. In other words, everyawait
inMyAsyncMethod
should end withConfigureAwait(false)
. This means it can't update any UI elements or access the ASP.NET request context.Solution B
If
MyAsyncMethod
does need to synchronize back to its context, then you may be able to useAsyncContext.RunTask
to provide a nested context:*Update 4/14/2014: In more recent versions of the library the API is as follows:
(It's OK to use
Task.Result
in this example becauseRunTask
will propagateTask
exceptions).The reason you may need
AsyncContext.RunTask
instead ofTask.WaitAndUnwrapException
is because of a rather subtle deadlock possibility that happens on WinForms/WPF/SL/ASP.NET:Task
.Task
.async
method usesawait
withoutConfigureAwait
.Task
cannot complete in this situation because it only completes when theasync
method is finished; theasync
method cannot complete because it is attempting to schedule its continuation to theSynchronizationContext
, and WinForms/WPF/SL/ASP.NET will not allow the continuation to run because the synchronous method is already running in that context.This is one reason why it's a good idea to use
ConfigureAwait(false)
within everyasync
method as much as possible.Solution C
AsyncContext.RunTask
won't work in every scenario. For example, if theasync
method awaits something that requires a UI event to complete, then you'll deadlock even with the nested context. In that case, you could start theasync
method on the thread pool:However, this solution requires a
MyAsyncMethod
that will work in the thread pool context. So it can't update UI elements or access the ASP.NET request context. And in that case, you may as well addConfigureAwait(false)
to itsawait
statements, and use solution A.Update: 2015 MSDN article 'Async Programming - Brownfield Async Development' by Stephen Cleary.