In some situations, we may need to run an async method and get its result. But we can't access the await
keyword.
- In the constructor method.
- When you are implementing an interface sync method.
- When you are implementing an abstract class sync method.
I got a solution to unwrap the async method and call it in the synchronous method.
First, put the following code anywhere you like:
using System.Threading;
using System.Threading.Tasks;
public static class AsyncHelper
{
private static readonly TaskFactory _taskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
=> _taskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
public static void RunSync(Func<Task> func)
=> _taskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
And create an async method like this:
private static async Task<int> MyAsyncMethod()
{
// do something async.
await Task.Delay(1000);
Console.WriteLine("Running in MyAsyncMethod");
return 2 + 3;
}
To call the async method: MyAsyncMethod
in a sync method, do it like this:
static void Main(string[] args)
{
var result = AsyncHelper.RunSync(async () =>
{
return await MyAsyncMethod();
});
Console.WriteLine(result);
}
Which outputs:
Running in MyAsyncMethod
5
Or more simply:
var result = AsyncHelper.RunSync(MyAsyncMethod)
Console.WriteLine(result);
Which outputs the same:
Running in MyAsyncMethod
5
By the way, if you don't have to wait it, and run the job in background, please reference: https://anduin.aiursoft.com/post/2020/10/14/fire-and-forget-in-aspnet-core-with-dependency-alive
If you want to run background job in a task queue and pool, please reference: https://anduin.aiursoft.com/post/2020/12/22/c-run-tasks-in-a-threads-pool-with-fixed-size
WHaT abOUT UsIng MYAsYnCMETHOd.WaIT() InsTEad Of TasKFaCTORY?
I for one have found the solution extremely helpful. I'm in the similar situation where I have to invoke async method from dependency class library which performs HTTP client communication. Invocation is issued from WPF app, from one of the controls event. Trying .wait() or .result with not awaitable call didn't help - internal call just hangs, waiting for completion event. Not sure why, I needed quick w/around and didn't have much time to figure out the internals. Probably because of some intricacies of WPF internal messages handling loop. Anyways, this solution works fine - task, created outside of handling loop, does the job. Kudos and Cheers !
This is great, but what if I want to pass parameters in to the async method?