I have a public async void Foo()
method that I want to call from 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: http://msdn.microsoft.com/en-us/library/hh300224(v=vs.110).aspx
Now I'm looking into calling these async methods from sync methods.
You can call any asynchronous method from synchronous code, that is, until you need to
await
on them, in which case they have to be markedasync
too.As a lot of people are suggesting here, you could call Wait() or Result on the resulting task in your synchronous method, but then you end up with a blocking call in that method, which sort of defeats the purpose of async.
I you really can't make your method
async
and you don't want to lock up the synchronous method, then you're going to have to use a callback method by passing it as parameter to the ContinueWith method on task.The most accepted answer is not entirely correct. There IS a solution that works in every situation: an ad-hoc message pump (SynchronizationContext).
The calling thread will be blocked as expected, while still ensuring that all continuations called from the async function don't deadlock as they'll be marshaled to the ad-hoc SynchronizationContext (message pump) running on the calling thread.
The code of the ad-hoc message pump helper:
Usage:
More detailed description of the async pump is available here.
To anyone paying attention to this question anymore...
If you look in
Microsoft.VisualStudio.Services.WebApi
there's a class calledTaskExtensions
. Within that class you'll see the static extension methodTask.SyncResult()
, which like totally just blocks the thread till the task returns.Internally it calls
task.GetAwaiter().GetResult()
which is pretty simple, however it's overloaded to work on anyasync
method that returnTask
,Task<T>
orTask<HttpResponseMessage>
... syntactic sugar, baby... daddy's got a sweet tooth.It looks like
...GetAwaiter().GetResult()
is the MS-official way to execute async code in a blocking context. Seems to work very fine for my use case.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.Adding a solution that finally solved my problem, hopefully saves somebody's time.
Firstly read a couple articles of Stephen Cleary:
From the "two best practices" in "Don't Block on Async Code", the first one didn't work for me and the second one wasn't applicable (basically if I can use
await
, I do!).So here is my workaround: wrap the call inside a
Task.Run<>(async () => await FunctionAsync());
and hopefully no deadlock anymore.Here is my code: