snippetcsharpCritical
How to call asynchronous method from synchronous method in C#?
Viewed 0 times
howfromasynchronousmethodcallsynchronous
Problem
I have a
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
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.Solution
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
You do not want to use
This solution is only appropriate if
Solution B
If
*Update 4/14/2014: In more recent versions of the library the API is as follows:
(It's OK to use
The reason you may need
This is one reason why it's a good idea to use
Solution C
However, this solution requires a
Update: 2015 MSDN article 'Async Programming - Brownfield Async Development' by Stephen Cleary.
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:var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();You do not want to use
Task.Wait or Task.Result because they wrap exceptions in AggregateException.This solution is only appropriate if
MyAsyncMethod does not synchronize back to its context. In other words, every await in MyAsyncMethod should end with ConfigureAwait(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 use AsyncContext.RunTask to provide a nested context:var result = AsyncContext.RunTask(MyAsyncMethod).Result;*Update 4/14/2014: In more recent versions of the library the API is as follows:
var result = AsyncContext.Run(MyAsyncMethod);(It's OK to use
Task.Result in this example because RunTask will propagate Task exceptions).The reason you may need
AsyncContext.RunTask instead of Task.WaitAndUnwrapException is because of a rather subtle deadlock possibility that happens on WinForms/WPF/SL/ASP.NET:- A synchronous method calls an async method, obtaining a
Task.
- The synchronous method does a blocking wait on the
Task.
- The
asyncmethod usesawaitwithoutConfigureAwait.
- The
Taskcannot complete in this situation because it only completes when theasyncmethod is finished; theasyncmethod 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 every async method as much as possible.Solution C
AsyncContext.RunTask won't work in every scenario. For example, if the async 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 the async method on the thread pool:var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();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 add ConfigureAwait(false) to its await statements, and use solution A.Update: 2015 MSDN article 'Async Programming - Brownfield Async Development' by Stephen Cleary.
Code Snippets
var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();var result = AsyncContext.RunTask(MyAsyncMethod).Result;var result = AsyncContext.Run(MyAsyncMethod);var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();Context
Stack Overflow Q#9343594, score: 1120
Revisions (0)
No revisions yet.