Problem
I want to call a public async void Foo() method from a synchronous method. All I’ve seen so far from MSDN documentation is async methods calling async methods, but my entire application isn’t designed with async methods.
Is it even possible to do so?
Here’s an example of an asynchronous method calling these methods: Walkthrough: Using Async and Await to Access the Web (C# and Visual Basic)
Now I’m trying to figure out how to invoke these async functions from sync methods.
Asked by Tower
Solution #1
Through the code base, asynchronous programming “grows.” It’s been likened to a zombie outbreak. The ideal option is to let it grow, although this isn’t always possible.
In my Nito.AsyncEx package, I have a few types for dealing with partially asynchronous code. However, there is no one-size-fits-all strategy that will work in every circumstance.
Solution A
You can use Task if you have a basic asynchronous method that doesn’t need to synchronize back to its context. WaitAndUnwrapException:
var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();
Task is not something you want to employ. Wait or perform a task. Because they wrap exceptions in AggregateException, they get this result.
If MyAsyncMethod does not synchronize back to its context, this solution is applicable. In other words, in MyAsyncMethod, every await should conclude with ConfigureAwait (false). It can’t update any UI components or access the ASP.NET request context because of this.
Solution B
You might be able to use AsyncContext if MyAsyncMethod needs to synchronize back to its context. To provide a nested context, use RunTask:
var result = AsyncContext.RunTask(MyAsyncMethod).Result;
*4/14/2014 Update: The API in more current versions of the library is as follows:
var result = AsyncContext.Run(MyAsyncMethod);
(It is acceptable to use Task.) Task exceptions will be propagated by RunTask in this case).
The reason you might want to use AsyncContext. Instead of Task, use RunTask. WaitAndUnwrapException occurs as a result of a minor stalemate that can occur in WinForms/WPF/SL/ASP.NET:
This is one of the reasons why it’s best to use ConfigureAwait(false) as much as possible in async methods.
Solution C
AsyncContext. RunTask isn’t going to work in every situation. Even with the nested context, you’ll jam if the async procedure awaits something that requires a UI event to complete. In that situation, you may use the thread pool to initiate the async method:
var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();
This solution, however, necessitates the use of a MyAsyncMethod that can work in a thread pool environment. As a result, it is unable to alter user interface components or access the ASP.NET request context. In that instance, you can apply solution A by adding ConfigureAwait(false) to its await statements.
Update, 2019-05-01: An MSDN post has the current “least-worst practices.”
Answered by Stephen Cleary
Solution #2
Including a solution that eventually addressed my problem in the hopes of saving someone’s time.
First, read a couple of Stephen Cleary articles:
The first of the “two recommended practices” in “Don’t Block on Async Code” didn’t work for me, and the second wasn’t applicable (essentially, if I can use await, why can’t I use await?).
So here’s how I got around it: Within a Task, wrap the call. Run>(async () => await FunctionAsync()); and hopefully there will be no deadlock.
My code is as follows:
public class LogReader
{
ILogger _logger;
public LogReader(ILogger logger)
{
_logger = logger;
}
public LogEntity GetLog()
{
Task<LogEntity> task = Task.Run<LogEntity>(async () => await GetLogAsync());
return task.Result;
}
public async Task<LogEntity> GetLogAsync()
{
var result = await _logger.GetAsync();
// more code here...
return result as LogEntity;
}
}
Answered by Tohid
Solution #3
To execute Async as Sync, Microsoft created an AsyncHelper (internal) class. The source appears to be:
internal static class AsyncHelper
{
private static readonly TaskFactory _myTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return AsyncHelper._myTaskFactory
.StartNew<Task<TResult>>(func)
.Unwrap<TResult>()
.GetAwaiter()
.GetResult();
}
public static void RunSync(Func<Task> func)
{
AsyncHelper._myTaskFactory
.StartNew<Task>(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
}
There are classes with extension methods that look like (example usage): Microsoft.AspNet.Identity base classes only have Async methods, and in order to call them Sync, there are classes with extension methods that look like (example usage):
public static TUser FindById<TUser, TKey>(this UserManager<TUser, TKey> manager, TKey userId) where TUser : class, IUser<TKey> where TKey : IEquatable<TKey>
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
return AsyncHelper.RunSync<TUser>(() => manager.FindByIdAsync(userId));
}
public static bool IsInRole<TUser, TKey>(this UserManager<TUser, TKey> manager, TKey userId, string role) where TUser : class, IUser<TKey> where TKey : IEquatable<TKey>
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
return AsyncHelper.RunSync<bool>(() => manager.IsInRoleAsync(userId, role));
}
For those concerned about the conditions of code licensing, here is a link to very comparable code (that simply adds support for culture to the thread) that has comments indicating that it is MIT Licensed by Microsoft. https://github.com/aspnet/AspNetIdentity/blob/master/src/Microsoft.AspNet.Identity.Core/AsyncHelper.cs
Absolutely not.
The simple answer is yes.
.Unwrap().GetAwaiter().GetResult() != .Result
First off the
Is.GetAwaiter.GetResult() the same as Task.Result?
The second point is. Unwrap() prevents the Job’s setup from blocking the wrapped task.
Which should prompt anyone to inquire.
This would be an It Depends situation.
In terms of Task.Start(), Task.Run(), and Task.Factory.StartNew, Task.Start(), Task.Run(), and Task.Factory.StartNew ()
Excerpt:
Additional Reading:
A synchronization context must be specified.
ASP.NET Core SynchronizationContext
Great point, and like with most object architectural concerns, the answer is it depends.
Do you want to impose it for every call as an extension method, or do you want to let the programmer using the function customize it for their own async calls? I could see a use case for call three scenarios; it’s probably not something you want in WPF, but it makes sense in most cases, and since there’s no Context in ASP.Net Core, it wouldn’t matter if you could assure it was internal for an ASP.Net Core.
Answered by Erik Philips
Solution #4
C# 7.2 now includes async Main, which may be enabled in the project’s advanced build options.
The right method for C# 7.2 is:
static void Main(string[] args)
{
MainAsync().GetAwaiter().GetResult();
}
static async Task MainAsync()
{
/*await stuff here*/
}
This is mentioned frequently in Microsoft documentation, such as https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dotnet-how-to-use-topics-subscriptions.
Answered by Lee Smith
Solution #5
public async Task<string> StartMyTask()
{
await Foo()
// code to execute once foo is done
}
static void Main()
{
var myTask = StartMyTask(); // call your method which will return control once it hits await
// now you can continue executing code here
string result = myTask.Result; // wait for the task to complete to continue
// use result
}
“Start this long-running process, then return control to the caller method,” you read the ‘await’ keyword as. It executes the code after the long-running process is completed. After the await, the code resembles what used to be CallBack methods. The main distinction is that the logical flow is not disrupted, making writing and reading considerably easier.
Answered by Despertar
Post is based on https://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in-c