1321

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:
Walkthrough: Accessing the Web by Using Async and Await (C# and Visual Basic)

Now I'm looking into calling these async methods from sync methods.

AminM
  • 1,658
  • 4
  • 32
  • 48
Tower
  • 98,741
  • 129
  • 357
  • 507
  • 4
    I ran into this as well. Overriding a RoleProvider you cannot change the method signature of the GetRolesForUser method so you can not make the method async and so cannot use await to call out to api asyncronously. My temporary solution was to add synchronous methods to my generic HttpClient class but would like to know if this is possible (and what the implications might be). – Timothy Lee Russell Aug 05 '12 at 04:16
  • 3
    Because your `async void Foo()` method does not return a `Task` it means a caller cannot know when it completes, it must return `Task` instead. – Dai May 07 '18 at 02:27
  • 1
    Linking a [related q/a](https://stackoverflow.com/q/53508160/1768303) on how to do this on a UI thread. – noseratio Nov 29 '18 at 01:11
  • 2
    I've used this method and seems to do the job: MyMethodAsync.GetAwaiter().GetResult(); Before that, you might want to check the following article that ends up boiling down to deadlocks and threadpool starvation: https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d – J.Tribbiani May 05 '22 at 17:40
  • @Timothy Lee Russell I don't think GetRolesForUser() should do much. Especially not call time consuming async methods. – The incredible Jan Oct 04 '22 at 11:58

18 Answers18

1054

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:

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:

  1. A synchronous method calls an async method, obtaining a Task.
  2. The synchronous method does a blocking wait on the Task.
  3. The async method uses await without ConfigureAwait.
  4. The Task cannot complete in this situation because it only completes when the async method is finished; the async method cannot complete because it is attempting to schedule its continuation to the SynchronizationContext, 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.

Andrew D. Bond
  • 902
  • 1
  • 11
  • 11
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • 22
    Solution A seems like what I want, but it looks like task.WaitAndUnwrapException() didn't make it into the .Net 4.5 RC; it only has task.Wait(). Any idea how to do this with the new version? Or is this a custom extension method you wrote? – deadlydog Jul 25 '12 at 23:17
  • 6
    `WaitAndUnwrapException` is my own method from my [AsyncEx library](http://nitoasyncex.codeplex.com/). The official .NET libs don't provide much help for mixing sync and async code (and in general, you shouldn't do it!). I'm waiting for .NET 4.5 RTW and a new non-XP laptop before updating AsyncEx to run on 4.5 (I cannot currently develop for 4.5 because I'm stuck on XP for a few more weeks). – Stephen Cleary Jul 25 '12 at 23:33
  • I have tried to use Nito.AsyncEx, but the `Task` Method gives me an ambiguity error... (It doesn't have RunkTask) How do I solve it? – Eric.M Jun 23 '13 at 06:16
  • 19
    `AsyncContext` now has a `Run` method that takes a lambda expression, so you should use `var result = AsyncContext.Run(() => MyAsyncMethod());` – Stephen Cleary Jun 23 '13 at 12:42
  • 1
    I got your library off Nuget, but it doesn't actually seem to have a `RunTask` method. Closest thing I could find was `Run`, but that doesn't have a `Result` property. – Asad Saeeduddin Apr 14 '14 at 23:43
  • 4
    @Asad: Yes, more than 2 years later the API has changed. [You can now simply say `var result = AsyncContext.Run(MyAsyncMethod);`](http://nitoasyncex.codeplex.com/wikipage?title=AsyncContext) – Stephen Cleary Apr 14 '14 at 23:55
  • Yes, I found that page after some digging around. Should have done more research before commenting. I've updated the answer to reflect the new API just in case someone else is lazy. – Asad Saeeduddin Apr 15 '14 at 00:14
  • @StephenCleary, I have a synchronous method calling async with `.Result`. It works fine when called via wcf or REST. But it fails when invoked via NUnit. How is this possible, if you could provide your comments. Thanks – Babu James Jun 29 '15 at 03:36
  • @BabuJames: It could be due to the fact that [async method continuations use the `ExecuteSynchronously` flag](http://blog.stephencleary.com/2012/12/dont-block-in-asynchronous-code.html); I explore this more on my blog. – Stephen Cleary Jun 29 '15 at 18:38
  • @StephenCleary Just wondering: what about: `T UnAsync(Task task)` `{` ` while (!task.IsCompleted)` ` {` ` Thread.Yield();` ` }` ` return task.Result;` `}` used like this: `var result = UnAsync(MyAsyncMethod())` ? – sonatique Mar 15 '16 at 15:51
  • @sonatique: That can easily hit 100% CPU with the busy-waiting loop. Also `Result` will wrap exceptions in an `AggregateException`. – Stephen Cleary Mar 15 '16 at 17:10
  • 1
    @StephenCleary: thanks a lot for your reply. Yes indeed, it should be used only where hitting 100% CPU is not an issue, or when one know that the operation won't last too long. Anyway when we have to do such async to sync we're already a little bit in a gray zone, right? My goal was to avoid creating a new task or thread, and to absolutely avoid .Wait/.Result since the function we're in may look "sync" but might have been called with an await somewhere up in the call stack... Regarding exceptions: yes indeed, my actual implementation use a try.catch and your PrepareForRethrow ;-) – sonatique Mar 16 '16 at 10:28
  • By the way, since I am using Thread.Yield() I assume that we'll hit 100% CPU only when there is noting else to do, such that we won't starve other threads; do you think am I correct? – sonatique Mar 16 '16 at 10:29
  • @sonatique: No, you'll always hit 100% CPU. Whether the context continues executing the `while` loop or whether it's doing something else, it'll always do *something*. – Stephen Cleary Mar 16 '16 at 11:21
  • @StephenCleary: yes ok, you're right. I did not write precisely what I meant: yes we'll hit 100%, so this could starve other processes, but I wanted to say that inside our process, we won't eat 100% of the CPU for looping around `!task.IsCompleted` when there are other things to do, so we won't starve other threads inside our process. – sonatique Mar 16 '16 at 11:36
  • 1
    @StephenCleary: one last question, thanks for your time., What about: `var semaphore = new SemaphoreSlim(0); task.ContinueWith(t => { semaphore.Release(); }, cancel); semaphore.Wait(cancel); task.Wait(cancel);` ? Any danger doing this if there is an await somewhere before in the call stack? – sonatique Mar 16 '16 at 11:37
  • @sonatique: That approach re-opens the possibility of deadlocks. There is no solution that works in all scenarios. – Stephen Cleary Mar 16 '16 at 14:38
  • @StephenCleary: thanks a lot! This is what I thought (after posting my question). I am thinking about a mixed solution for my use case: wrapping the semaphore things within a `while(!task.IsCompleted)` loop and letting the semaphore quit waiting every, say, 100ms, using `semaphore.Wait(100)`. This would avoid the 100% CPU thing, while avoiding deadlock, at the price of a possible 100ms "temporary deadlock". Thanks again! – sonatique Mar 16 '16 at 16:09
  • 1
    Be warned that using ConfigureAwait(false) will not preserve the current culture and UI culture. That's why the entity framework staff added the WithCurrentCulture extension. – Maly Lemire Jun 21 '16 at 19:56
  • 1
    @StephenCleary Is there any update to this answer after some years? would you still recommend this solution today? – Saber Jan 17 '17 at 09:37
  • 1
    @Arvand: I have a more recent [MSDN article](https://msdn.microsoft.com/en-us/magazine/mt238404.aspx) on the subject. – Stephen Cleary Jan 17 '17 at 13:59
  • 2
    [Here](https://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html) @StephenCleary explains that GetAwaiter().GetResult() is a good alternative. – Orhan Oct 16 '17 at 15:25
  • @StephenCleary: I have been reading in [some](https://stackoverflow.com/a/19696462/2990310) posts that Task.FromResult can be used to call asynchronous methods in synchronous implementation. Can't we use it in this scenario? – Saket Kumar Nov 22 '17 at 08:10
  • @Saket: I no longer recommend using it for that, due to the different error handling semantics. See my article on [brownfield async](https://msdn.microsoft.com/en-us/magazine/mt238404.aspx) if you absolutely cannot avoid sync-over-async. – Stephen Cleary Nov 25 '17 at 00:05
  • 1
    got error Task' does not contain a definition for 'WaitAndUnwrapException' and no accessible extension method 'WaitAndUnwrapException' accepting a first argument of type 'Task' could be found (are you missing a using directive or an assembly reference?) any ideas?? – B''H Bi'ezras -- Boruch Hashem Feb 06 '20 at 04:43
  • 8
    @bluejayke: Install the [`Nito.AsyncEx`](https://github.com/StephenCleary/AsyncEx) library. Alternatively, use `.GetAwaiter().GetResult()` instead of `.WaitAndUnwrapException()`. – Stephen Cleary Feb 06 '20 at 14:03
  • 1
    @StephenCleary interesting, I tried .GetAwaiter().GetResult(), but afterwards, I realized that I need a new way of doing it. Meaning insttead of atempting to reporoduce the "await" keyword, I need a way to repordouce the JavaScripts Promise .then, for example, in C#, is there some way to call an asynchrous function like: myAsyncFunc("hello").Then(r=>/*something*/) ? – B''H Bi'ezras -- Boruch Hashem Feb 06 '20 at 22:00
  • @bluejayke: `await` is the most modern form of `then`. Is there some reason you can't use `await`? – Stephen Cleary Feb 07 '20 at 13:25
  • 1
    @StephenCleary await is not the same as then, because await can only be called in an async function, and when calling await, it freezes the main loop; however, "then" is the opposite of await, since, even though you are calling a function that would normally be called with "await", but it can #1 be done in a regular function and #2 not clog up the main loop – B''H Bi'ezras -- Boruch Hashem Feb 10 '20 at 00:17
  • @bluejayke: Both `await` and `then` attach continuations. `await` is a more modern syntax for attaching continuations that handles corner cases well and results in more maintainable code. Calling `then` and then discarding the resulting continuation `Task` is functionally equivalent to calling an `async` method and discarding the returned `Task` (and neither is recommended). – Stephen Cleary Feb 10 '20 at 02:33
  • Would have loved to read this before doing my own thing... which probably is worse and longer... `protected T DoTheSync(Task task) { try { return task.Result; } catch (AggregateException e) when (e.InnerException != null) { ExceptionDispatchInfo.Capture(e.InnerException).Throw(); throw; } }` (sorry for not being able to post properly indented code here :-) ) – Loudenvier Jul 31 '20 at 12:06
  • How about AsyncMethod().RunSynchronously(); ?? – Macindows Aug 02 '20 at 20:31
  • 1
    @Macindows: `RunSynchronously` is for delegate tasks; it doesn't work with tasks returned from asynchronous methods. – Stephen Cleary Aug 02 '20 at 21:31
  • Can we use sol 2 or 3 in VM constructor in MVVM which loads UI or sets properties? – Morse Jan 28 '21 at 15:14
  • 1
    @Morse: I don't recommend blocking UI threads. You should instead show a "Loading..." screen while loading the data. – Stephen Cleary Jan 28 '21 at 19:07
  • @StephenCleary when you say "every await in MyAsyncMethod should end with ConfigureAwait(false)" - do you mean "every await ALL THE WAY DOWN" or just every await at MyAsyncMethod level? – Alex from Jitbit Aug 20 '22 at 09:44
  • 1
    @AlexfromJitbit Every await all the way down. Every await in MyAsyncMethod and the transitive closure of all methods called from it. Including all third-party libraries and framework code. The obvious problem with that approach is it's easy to miss one. – Stephen Cleary Aug 20 '22 at 13:14
  • @StephenCleary Can you please explain difference b/w below and tell me that which one is least worst ? #1 Task.Run(() => SomeLibrary.FooAsync()).Result; #2 Task.Run(() => SomeLibrary.FooAsync().Result).Result; #3 Task.Run(async () => await SomeLibrary.FooAsync()).Result; #4 Task.Run(async () => await SomeLibrary.FooAsync().ConfigureAwait(false)).Result; – Jay Shah Nov 14 '22 at 21:02
  • @JayShah: I recommend asking your own question, also providing application details. Comments aren't a good medium for giving answers – Stephen Cleary Nov 14 '22 at 23:50
423

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:

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;
    }
}
Tohid
  • 6,175
  • 7
  • 51
  • 80
  • 9
    Two years on, I'm curious to know how this solution is holding up. Any news? Is there subtlety to this approach that is lost on newbies? – Dan Esparza Aug 18 '17 at 12:17
  • What happens when there is an exception in `GetLog()` -- does it throw an [AggregateException](https://msdn.microsoft.com/en-us/library/system.aggregateexception(v=vs.110).aspx)? – Dan Esparza Aug 18 '17 at 12:22
  • If the exception is inside the `GetLog()` itself, it raises as a normal exception. But if it raises inside `GetLogAsync()`, you can get it from `task.Exception` property. The document is here: https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.exception(v=vs.110).aspx – Tohid Aug 18 '17 at 20:16
  • 52
    This won't deadlock, true, but simply because it's forced to run in a new thread, outside of the synchronization context of the originating thread. However, there's certain environments where this is very ill-advised: particularly web applications. This could effectively halve the available threads for the web server (one thread for the request and one for this). The more you do this, the worse it gets. You could potentially end up deadlocking your entire web server. – Chris Pratt Oct 11 '17 at 14:16
  • 62
    @ChrisPratt - You may be right, because `Task.Run()` is not a best practice in an async code. But, again, what's the answer to the original question? Never call an async method synchronously? We wish, but in a real world, sometimes we have to. – Tohid Oct 28 '17 at 06:44
  • Trying this method on an SqlCommand generates a System.Reflection.TargetInvocationException for me: `Task.Run(async () => await command.ExecuteNonQueryAsync());` Adding assignments as you did solved the problem: `Task task = Task.Run(async () => await command.ExecuteNonQueryAsync()); var result = task.Result;` – Pete Nov 14 '17 at 09:10
  • 2
    @Tohid you could try Stephen Cleary's library. I've seen people assume this and `Parallel.ForEach` abuse won't have an effect in 'the real world' and eventually it took down the servers. This code is OK for Console apps but as @ChrisPratt says, shouldn't be used in Web Apps. It might work "now" but isn't scalable. – makhdumi Nov 21 '17 at 18:00
  • 1
    if `GetLogAsync()` throws an exception we can't simply catch it using a `try / catch` in `GetLog()`. I mean, it will catch the exception, but it won't be the original one. – empz Nov 09 '18 at 18:53
  • @emzero - that's a fallback I guess. Do you have any solution? – Tohid Nov 10 '18 at 08:30
  • 54
    Kinda crazy that .NET 5.0 is out and there's still no bulletproof way to call async methods synchronously. – Mass Dot Net Nov 17 '20 at 17:52
  • What's the difference between `Task task = Task.Run(async () => await GetLogAsync()); return task.Result;` and simply `return GetLogAsync().Result;`? – JHBonarius Jan 08 '21 at 07:54
  • 4
    @JHBonarius In the first case, the task is performed on a background thread and the result is fetched by the originating context, through the `Result` property. In the second case, the task is performed on the same context and will lead to a deadlock if that context is the UI Thread. – AsPas Sep 03 '21 at 08:18
  • @AsPas yeah thanks. in the past 8 months I learned a lot of C#, so in the mean time I know that. (The hard way, resulting in a deadlock). Still good of you to put it here – JHBonarius Sep 04 '21 at 09:55
304

Microsoft built an AsyncHelper (internal) class to run Async as Sync. The source looks like:

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();
    }
}

The Microsoft.AspNet.Identity base classes only have Async methods and in order to call them as 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 licensing terms of code, here is a link to very similar code (just adds support for culture on the thread) that has comments to indicate that it is MIT Licensed by Microsoft. https://github.com/aspnet/AspNetIdentity/blob/master/src/Microsoft.AspNet.Identity.Core/AsyncHelper.cs

Wouldn't this be the same as just calling Task.Run(async ()=> await AsyncFunc()).Result? AFAIK, Microsoft is now discouraging from calling TaskFactory.StartNew, since they are both equivalent and one is more readable than the other.

Absolutely not.

The easy answer is that

.Unwrap().GetAwaiter().GetResult() != .Result

First off the

Is Task.Result the same as .GetAwaiter.GetResult()?

Secondly .Unwrap() causes the setup of the Task not to block the wrapped task.

Which should lead anyone to ask

Wouldn't this be the same as just calling Task.Run(async ()=> await AsyncFunc()).GetAwaiter().GetResult()

Which would then be a It Depends.

Regarding usage of Task.Start() , Task.Run() and Task.Factory.StartNew()

Excerpt:

Task.Run uses TaskCreationOptions.DenyChildAttach which means that children's tasks can not be attached to the parent and it uses TaskScheduler.Default which means that the one that runs tasks on Thread Pool will always be used to run tasks.

Task.Factory.StartNew uses TaskScheduler.Current which means scheduler of the current thread, it might be TaskScheduler.Default but not always.

Additional Reading:

Specifying a synchronization context

ASP.NET Core SynchronizationContext

For extra safety, wouldn't it be better to call it like this AsyncHelper.RunSync(async () => await AsyncMethod().ConfigureAwait(false)); This way we're telling the "inner" method "please don't try to sync to upper context and dealock"

Really great point by alex-from-jitbit and as most object architectural questions go it depends.

As an extension method do you want to force that for absolutely every call, or do you let the programmer using the function configure that on their own async calls? I could see a use case for call three scenarios; it most likely is not something you want in WPF, certainly makes sense in most cases, but considering there is no Context in ASP.Net Core if you could guarantee it was say internal for a ASP.Net Core, then it wouldn't matter.

starball
  • 20,030
  • 7
  • 43
  • 238
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • 4
    My async methods await other async methods. I do NOT decorate any of my `await` calls with `ConfigureAwait(false)`. I tried using `AsyncHelper.RunSync` to call an async function from the `Application_Start()` function in Global.asax and it seems to work. Does this mean that `AsyncHelper.RunSync` is reliably not prone to the "marshal back to the caller's context" deadlock issue I read about elsewhere in this posting? – Bob.at.Indigo.Health May 21 '15 at 23:00
  • 1
    @Bob.at.SBS depends on what you code does. It's not as simple as *if I use this code am I safe*. This is very minimal and semi-safe way to run async commands synchronously, it can be easily used inappropriately to cause deadlocks. – Erik Philips May 22 '15 at 03:56
  • 1
    Thanks. 2 follow-up questions: 1) Can you give an example of something the async method wants to avoid that would cause a deadlock, and 2) are deadlocks in this context often timing-dependent? If it works in practice, might I still have a timing-dependent deadlock lurking in my code? – Bob.at.Indigo.Health May 23 '15 at 04:57
  • @Bob.at.SBS I would recommend asking question by using the *Ask Question* button at the top right. You can include a link to this question or answer in your question as a reference. – Erik Philips Sep 15 '15 at 16:27
  • `GetAwaiter` does not exist, anyone? – JobaDiniz Jun 13 '16 at 20:19
  • 1
    @Bob.at... the code provided by Erik works perfect under Asp. net mvc5 and EF6, but not when I tried any of the other solutions (ConfigureAwait(false).GetAwaiter().GetResult() or .result) which hangs completely my web app – LeonardoX Sep 17 '17 at 01:50
  • 1
    This is the only answer that does not cause deadlocks for my usage scenarios. – Aidan Aug 09 '20 at 08:46
  • 1
    Wouldn't this be the same as just calling `Task.Run(async ()=> await AsyncFunc()).Result`? AFAIK, Microsoft is now discouraging from calling `TaskFactory.StartNew`, since they are both equivalent and one is more readable than the other. Source: https://devblogs.microsoft.com/pfxteam/task-run-vs-task-factory-startnew/ – AsPas Sep 03 '21 at 08:20
  • 1
    For extra safety, wouldn't it be better to call it like this `AsyncHelper.RunSync(async () => await AsyncMethod().ConfigureAwait(false));` This way we're telling the "inner" method "please don't try to sync to upper context and dealock" – Alex from Jitbit Sep 08 '21 at 15:23
  • 1
    @AlexfromJitbit Great point, updated question! – Erik Philips Sep 08 '21 at 21:03
  • @ErikPhilips thanks for updating the already great answer. Regarding your last point about ASP.NET Core not having context - well, we do experience thread starvation by using this code as is. And we're not alone: https://github.com/aspnet/KestrelHttpServer/issues/2104#issuecomment-337479468 Just for adding context – Alex from Jitbit Sep 09 '21 at 16:40
  • No traces of AsyncHelper anymore (at least in .NET Core 5 source code). I suppose there are reasons for it – g.pickardou Nov 01 '21 at 14:00
  • Please note that newbedev is a Stack Overflow scraper; please don't link to it. Instead, google the text (possibly with `site:stackoverflow.com`) and find the correct on-site link, instead of giving scrapers more traffic that they don't deserve. – Zoe Dec 26 '21 at 14:53
  • @Zoe 100% agreed. Not sure how that happened, thanks for fixing it! – Erik Philips Dec 27 '21 at 05:21
  • @ErikPhilips Can you please explain difference b/w below and tell me that which one is least worst ? #1 Task.Run(() => SomeLibrary.FooAsync()).Result; #2 Task.Run(() => SomeLibrary.FooAsync().Result).Result; #3 Task.Run(async () => await SomeLibrary.FooAsync()).Result; #4 Task.Run(async () => await SomeLibrary.FooAsync().ConfigureAwait(false)).Result; Am I correct to think that #3 is least worst ? – Jay Shah Nov 14 '22 at 21:06
  • @JayShah All I will say is that I would never use of those. – Erik Philips Nov 18 '22 at 17:14
259

async Main is now part of C# 7.2 and can be enabled in the projects advanced build settings.

For C# < 7.2, the correct way is:

static void Main(string[] args)
{
   MainAsync().GetAwaiter().GetResult();
}


static async Task MainAsync()
{
   /*await stuff here*/
}

You'll see this used in a lot of Microsoft documentation, for example: https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dotnet-how-to-use-topics-subscriptions

Lee Smith
  • 6,339
  • 6
  • 27
  • 34
  • 22
    I have no idea WHY someone voted this down. This worked great for me. Without this fix, I would have had to propagate ASYCH EVERYWHERE. – Prisoner ZERO Jun 28 '15 at 01:14
  • 20
    Why is this better than `MainAsync().Wait()`? – crush Oct 28 '15 at 23:05
  • Yeah, there's no reason to it this roundabout way instead of using it like @crush said. However, the problem with this approach is that it does not allow for return types. You'd need more code for that. But the extension methods in the top answer take care of this (and unwraps the exceptions), so is superior to use unless you cannot for some reason. – Kat Dec 07 '15 at 21:41
  • 13
    I agree. You just need MainAsync().Wait() instead of all this. – Hajjat Dec 24 '15 at 03:23
  • 1
    @crush This pattern can help avoid deadlocks in some situations. Results can be returned by switching to .Result. – David Feb 01 '16 at 19:45
  • @crush If this were a UI app instead of console app* a deadlock could occur trying to .Wait() a task on the UI thread. Task.Run schedules the task to run on the threadpool. Now the await will capture the threadpool's context instead. The .Wait() will synchronously block the UI thread, but the task will complete on the threadpool. This avoids a deadlock *"in some situations". – David Feb 03 '16 at 01:39
  • @David That's not a deadlock. It's just blocking the UI thread. It'll eventually unblock the UI thread unless the task never completes. Sure, it's better to move the task off the UI thread in that scenario. I don't see how a deadlock occurs though. – crush Feb 03 '16 at 18:50
  • 13
    @crush I was describing how this can avoid some deadlocks. In some situations calling .Wait() from a UI or asp.net thread causes a deadlock. [async deadlocks](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html) – David Feb 03 '16 at 20:02
  • 8
    @ClintB: You should absolutely not do this in ASP.NET Core. Web applications are particularly vulnerable to being thread-starved, and each time you do this, you're pulling a thread from the pool that would otherwise be used to serve a request. It's less problematic for desktop/mobile applications because they're traditionally single-user. – Chris Pratt Oct 11 '17 at 14:20
  • @ChrisPratt You mean async shouldn't be used for web applications? using async is all over the ASP.NET Core documentation, is the reason why I am here trying to figure this out. What should we do when the official documentation is the one telling us to use async? for example, I am here because I'm trying to create a ViewComponent and the example they show all the code for is using async. I am confused now. – delroh Dec 14 '18 at 08:43
  • 1
    @delroh: I think some comments were removed. I'm reasonably sure I was replying to someone suggesting the use of `Task.Run`. Of course you can use async, and in ASP.NET Core, you should virtually always use async. – Chris Pratt Dec 14 '18 at 12:20
  • 1
    This hangs my UWP app. – FLICKER Jan 28 '19 at 17:26
  • This is basically the same as using `.Result`, which can cause Deadlocks. Agree with you guys, in a void Method, call `Wait()`. – seven Apr 01 '19 at 08:59
  • 4
    Wait() collects exceptions into an AggregateException, GetAwaiter().GetResult() returns the exception thrown. – Lee Smith Apr 02 '19 at 13:47
  • this is async call with synchronous execution – Damir Beylkhanov Aug 15 '19 at 15:57
  • there is a chance to get some error like this Could not load file or assembly 'Microsoft.Graph.Core, Version=1.14.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) – Amal Ps Dec 13 '19 at 06:11
  • 1
    This does not answer the original question which is "How to call async method from sync method?" You just changed the calling method to an async. – stackoverblown Apr 17 '21 at 14:20
  • 1
    This is the way to go if you are not calling from an UI thread, since it doesn't unnecessarily use more threads. – AsPas Sep 03 '21 at 08:24
  • 2
    This great answer is just the same as the accepted answer from Stephen Cleary, updated for 2021, as in his own comments, but without all the complicated "explanations". Yes, in e.g. web apps this might be not a good practice, async stuff is not invented without reason, but if you need to call an async method in a sync env, this is it. – Roland Jan 04 '22 at 12:01
75

I'm not 100% sure, but I believe the technique described in this blog should work in many circumstances:

You can thus use task.GetAwaiter().GetResult() if you want to directly invoke this propagation logic.

Pang
  • 9,564
  • 146
  • 81
  • 122
NStuke
  • 1,001
  • 8
  • 11
  • 11
    Solution A in Stephen Cleary's [answer](http://stackoverflow.com/a/9343733/450913) above uses this method. See [WaitAndUnwrapException](https://github.com/StephenCleary/AsyncEx/blob/edb2c6b66d41471008a56e4098f9670b5143617e/src/Nito.AsyncEx.Tasks/SynchronousTaskExtensions.cs#L17-L22) source. – orad Mar 29 '17 at 17:30
  • do you need use GetResult() if the function you are calling is void or task? I mean if you dont want to get any results back – Emil Jul 04 '17 at 16:47
  • 1
    Yes, otherwise it will not block until task completion. Alternatively instead of calling GetAwaiter().GetResult() you can call .Wait() – NStuke Jul 11 '17 at 00:57
  • 2
    That's the "many circumstances" part. It depends on the overall threading model and what other threads are doing to determine if there's a risk of deadlock or not. – NStuke Mar 29 '18 at 04:09
  • GetAwaiter().GetResult() can still cause deadlocks. It only unwraps the exception into a more sensible one. – nawfal Jun 05 '20 at 12:56
  • GetAwaiter().GetResult() causes deadlocks always for me also always. – Aidan Aug 09 '20 at 08:45
  • @orad yes, it may be using the "solution A" but without any dependencies from a 3rd party lib – Alex from Jitbit Aug 18 '20 at 16:25
68
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

}

You read the 'await' keyword as "start this long running task, then return control to the calling method". Once the long-running task is done, then it executes the code after it. The code after the await is similar to what used to be CallBack methods. The big difference being the logical flow is not interrupted which makes it much easier to write and read.

Despertar
  • 21,627
  • 11
  • 81
  • 79
  • 24
    `Wait` wraps exceptions and has the possibility of a deadlock. – Stephen Cleary Feb 18 '12 at 18:17
  • I thought if you called an async method without using `await`, it would be executed synchronously. At least that works for me (without calling `myTask.Wait`). Actually, I got an exception when I tried to call `myTask.RunSynchronously()` because it had already been executed! – awe Mar 11 '13 at 10:44
  • Note: You can then get the result of type `T` by calling myTask.Result() after the Wait() – Eric J. Oct 19 '13 at 15:38
  • Good point. I've changed `Wait()` to `Result` since this will also block until the task is finished. – Despertar Oct 20 '13 at 18:01
  • 3
    Should this answer still work as of today? I just tried it in an MVC Razor project and the app just hangs on accessing `.Result`. – iCollect.it Ltd Feb 23 '15 at 15:24
  • @awe That's a very special case - your task finished synchronously before it even got to the first `await`, basically - it wasn't asynchronous at all. `RunSynchronously` doesn't really do what most people think it does - you shouldn't really need it, ever. `Result` (and `Wait`) is the thing that synchronously waits for the task to complete - but it gets you in trouble if there's marshalling to the original synchronization context that you're blocking now with your `Wait` :) – Luaan Feb 23 '15 at 17:36
  • 8
    @TrueBlueAussie That's the synchronization context deadlock. Your async code marshalls back to the synchronization context, but that's being blocked by the `Result` call at the time, so it never gets there. And `Result` never ends, because it's waiting for someone who's waiting for the `Result` to end, basically :D – Luaan Feb 23 '15 at 17:37
32

There is, however, a good solution that works in (almost: see comments) 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:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Threading
{
    /// <summary>Provides a pump that supports running asynchronous methods on the current thread.</summary>
    public static class AsyncPump
    {
        /// <summary>Runs the specified asynchronous method.</summary>
        /// <param name="asyncMethod">The asynchronous method to execute.</param>
        public static void Run(Action asyncMethod)
        {
            if (asyncMethod == null) throw new ArgumentNullException("asyncMethod");

            var prevCtx = SynchronizationContext.Current;
            try
            {
                // Establish the new context
                var syncCtx = new SingleThreadSynchronizationContext(true);
                SynchronizationContext.SetSynchronizationContext(syncCtx);

                // Invoke the function
                syncCtx.OperationStarted();
                asyncMethod();
                syncCtx.OperationCompleted();

                // Pump continuations and propagate any exceptions
                syncCtx.RunOnCurrentThread();
            }
            finally { SynchronizationContext.SetSynchronizationContext(prevCtx); }
        }

        /// <summary>Runs the specified asynchronous method.</summary>
        /// <param name="asyncMethod">The asynchronous method to execute.</param>
        public static void Run(Func<Task> asyncMethod)
        {
            if (asyncMethod == null) throw new ArgumentNullException("asyncMethod");

            var prevCtx = SynchronizationContext.Current;
            try
            {
                // Establish the new context
                var syncCtx = new SingleThreadSynchronizationContext(false);
                SynchronizationContext.SetSynchronizationContext(syncCtx);

                // Invoke the function and alert the context to when it completes
                var t = asyncMethod();
                if (t == null) throw new InvalidOperationException("No task provided.");
                t.ContinueWith(delegate { syncCtx.Complete(); }, TaskScheduler.Default);

                // Pump continuations and propagate any exceptions
                syncCtx.RunOnCurrentThread();
                t.GetAwaiter().GetResult();
            }
            finally { SynchronizationContext.SetSynchronizationContext(prevCtx); }
        }

        /// <summary>Runs the specified asynchronous method.</summary>
        /// <param name="asyncMethod">The asynchronous method to execute.</param>
        public static T Run<T>(Func<Task<T>> asyncMethod)
        {
            if (asyncMethod == null) throw new ArgumentNullException("asyncMethod");

            var prevCtx = SynchronizationContext.Current;
            try
            {
                // Establish the new context
                var syncCtx = new SingleThreadSynchronizationContext(false);
                SynchronizationContext.SetSynchronizationContext(syncCtx);

                // Invoke the function and alert the context to when it completes
                var t = asyncMethod();
                if (t == null) throw new InvalidOperationException("No task provided.");
                t.ContinueWith(delegate { syncCtx.Complete(); }, TaskScheduler.Default);

                // Pump continuations and propagate any exceptions
                syncCtx.RunOnCurrentThread();
                return t.GetAwaiter().GetResult();
            }
            finally { SynchronizationContext.SetSynchronizationContext(prevCtx); }
        }

        /// <summary>Provides a SynchronizationContext that's single-threaded.</summary>
        private sealed class SingleThreadSynchronizationContext : SynchronizationContext
        {
            /// <summary>The queue of work items.</summary>
            private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> m_queue =
                new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
            /// <summary>The processing thread.</summary>
            private readonly Thread m_thread = Thread.CurrentThread;
            /// <summary>The number of outstanding operations.</summary>
            private int m_operationCount = 0;
            /// <summary>Whether to track operations m_operationCount.</summary>
            private readonly bool m_trackOperations;

            /// <summary>Initializes the context.</summary>
            /// <param name="trackOperations">Whether to track operation count.</param>
            internal SingleThreadSynchronizationContext(bool trackOperations)
            {
                m_trackOperations = trackOperations;
            }

            /// <summary>Dispatches an asynchronous message to the synchronization context.</summary>
            /// <param name="d">The System.Threading.SendOrPostCallback delegate to call.</param>
            /// <param name="state">The object passed to the delegate.</param>
            public override void Post(SendOrPostCallback d, object state)
            {
                if (d == null) throw new ArgumentNullException("d");
                m_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
            }

            /// <summary>Not supported.</summary>
            public override void Send(SendOrPostCallback d, object state)
            {
                throw new NotSupportedException("Synchronously sending is not supported.");
            }

            /// <summary>Runs an loop to process all queued work items.</summary>
            public void RunOnCurrentThread()
            {
                foreach (var workItem in m_queue.GetConsumingEnumerable())
                    workItem.Key(workItem.Value);
            }

            /// <summary>Notifies the context that no more work will arrive.</summary>
            public void Complete() { m_queue.CompleteAdding(); }

            /// <summary>Invoked when an async operation is started.</summary>
            public override void OperationStarted()
            {
                if (m_trackOperations)
                    Interlocked.Increment(ref m_operationCount);
            }

            /// <summary>Invoked when an async operation is completed.</summary>
            public override void OperationCompleted()
            {
                if (m_trackOperations &&
                    Interlocked.Decrement(ref m_operationCount) == 0)
                    Complete();
            }
        }
    }
}

Usage:

AsyncPump.Run(() => FooAsync(...));

More detailed description of the async pump is available here.

Robert J
  • 704
  • 10
  • 8
23

To anyone paying attention to this question anymore...

If you look in Microsoft.VisualStudio.Services.WebApi there's a class called TaskExtensions. Within that class you'll see the static extension method Task.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 any async method that return Task, Task<T> or Task<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.

jrypkahauer
  • 538
  • 5
  • 8
15
var result = Task.Run(async () => await configManager.GetConfigurationAsync()).ConfigureAwait(false);

OpenIdConnectConfiguration config = result.GetAwaiter().GetResult();

Or use this:

var result=result.GetAwaiter().GetResult().AccessToken
Andrew Myers
  • 2,754
  • 5
  • 32
  • 40
rajesh A
  • 373
  • 4
  • 10
14

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 marked as async 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.

If 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.

Paul
  • 571
  • 3
  • 17
base2
  • 983
  • 9
  • 13
  • 11
    Then that wouldn't be calling the method synchronously now would it? – Jeff Mercado Feb 18 '12 at 18:05
  • 6
    As I understand, the question was can you call an async method from a non-async method. This does not imply having to call the async method in a blocking manner. – base2 Feb 18 '12 at 18:23
  • 2
    Sorry, your "they have to be marked `async` too" drew my attention away from what you were really saying. – Jeff Mercado Feb 18 '12 at 22:56
  • 2
    If I don't really care about the asynchronousness, is it OK to call it this way (and what about the possibility of deadlocks in wrapped exceptions that Stephen Cleary keeps nagging about?) I have some test methods (that must be executed synchronously) that tests asynchronous methods. I must wait for the result before continuing, so I can test the result of the asynchronous method. – awe Mar 11 '13 at 11:20
13

Here is the simplest solution. I saw it somewhere on the Internet, I didn't remember where, but I have been using it successfully. It will not deadlock the calling thread.

    void SynchronousFunction()
    {
        Task.Run(Foo).Wait();
    }

    string SynchronousFunctionReturnsString()
    {
        return Task.Run(Foo).Result;
    }

    string SynchronousFunctionReturnsStringWithParam(int id)
    {
        return Task.Run(() => Foo(id)).Result;
    }
panpawel
  • 1,782
  • 1
  • 16
  • 17
10

Stephen Cleary's Answer;

That approach shouldn't cause a deadlock (assuming that ProblemMethodAsync doesn't send updates to the UI thread or anything like that). It does assume that ProblemMethodAsync can be called on a thread pool thread, which is not always the case.

https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

And here is the approach;

The Thread Pool Hack A similar approach to the Blocking Hack is to offload the asynchronous work to the thread pool, then block on the resulting task. The code using this hack would look like the code shown in Figure 7.

Figure 7 Code for the Thread Pool Hack

C#

public sealed class WebDataService : IDataService
{
  public string Get(int id)
  {
    return Task.Run(() => GetAsync(id)).GetAwaiter().GetResult();
  }
  public async Task<string> GetAsync(int id)
  {
    using (var client = new WebClient())
      return await client.DownloadStringTaskAsync(
      "https://www.example.com/api/values/" + id);
  }
}

The call to Task.Run executes the asynchronous method on a thread pool thread. Here it will run without a context, thus avoiding the deadlock. One of the problems with this approach is the asynchronous method can’t depend on executing within a specific context. So, it can’t use UI elements or the ASP.NET HttpContext.Current.

Hubeyb Özkul
  • 646
  • 7
  • 8
8

Inspired by some of the other answers, I created the following simple helper methods:

public static TResult RunSync<TResult>(Func<Task<TResult>> method)
{
    var task = method();
    return task.GetAwaiter().GetResult();
}

public static void RunSync(Func<Task> method)
{
    var task = method();
    task.GetAwaiter().GetResult();
}

They can be called as follows (depending on whether you are returning a value or not):

RunSync(() => Foo());
var result = RunSync(() => FooWithResult());

Note that the signature in the original question public async void Foo() is incorrect. It should be public async Task Foo() as you should return Task not void for async methods that don't return a value (yes, there are some rare exceptions).

Metalogic
  • 498
  • 6
  • 16
  • I had to change the method to be like this for it to work: `return Task.Run(async () => await method()).GetAwaiter().GetResult();` – herdsothom Sep 14 '21 at 00:37
  • @herdsothom that's because in your case `method()` is actually an asyncrounous method itself - while in @Metalogic's example `foo()` is a syncrounous method that he is calling asyncrounously. In your case simply `method().GetAwaiter().GetResult();` should sufice – 537mfb Sep 24 '21 at 09:26
4

Well I was using this approach for years, which also handles and propagates exceptions from the underlying async task. Which works flawlessly.

private string RunSync()
{
    var task = Task.Run(async () => await GenerateCodeService.GenerateCodeAsync());
    if (task.IsFaulted && task.Exception != null)
    {
        throw task.Exception;
    }

    return task.Result;
}

But since that Microsoft created this async helper: https://github.com/aspnet/AspNetIdentity/blob/main/src/Microsoft.AspNet.Identity.Core/AsyncHelper.cs

Here is also their source:

public static void RunSync(Func<Task> func)
        {
            var cultureUi = CultureInfo.CurrentUICulture;
            var culture = CultureInfo.CurrentCulture;
            _myTaskFactory.StartNew(() =>
            {
                Thread.CurrentThread.CurrentCulture = culture;
                Thread.CurrentThread.CurrentUICulture = cultureUi;
                return func();
            }).Unwrap().GetAwaiter().GetResult();
        }
Jiří Herník
  • 2,412
  • 1
  • 25
  • 26
0

You can now use source generators to create a sync version of your method using Sync Method Generator library (nuget).

Use it as follows:

[Zomp.SyncMethodGenerator.CreateSyncVersion]
public async void FooAsync()

Which will generate Foo method which you can call synchronously.

Victor Irzak
  • 59
  • 2
  • 4
0

Everyone seems to presuppose that there is a need to wait for the result. I often have to update data from synchronous methods where I don't care about the result. I just use a discard:

_ = UpdateAsync();
The incredible Jan
  • 741
  • 10
  • 17
  • this is wrong sorry, it means, it's not guaranteed, that the code inside will run to an end. if the main() will reach an end of execution, it will not look after the code inside if it's done or not, and will just shut it down. – Jiří Herník Jul 27 '23 at 09:54
  • @JiříHerník I have a project where data lists (tables that the usere sees and uses to pick existing records) in the client are loaded async. Why should it matter if the code finishes before the user closes the application? Maybe "wait for the result" isn't the best possible expression... – The incredible Jan Aug 15 '23 at 13:34
  • 1
    The code inside not awaited async task is not quarantined to finish. That is all. – Jiří Herník Aug 26 '23 at 09:43
-3

Those windows async methods have a nifty little method called AsTask(). You can use this to have the method return itself as a task so that you can manually call Wait() on it.

For example, on a Windows Phone 8 Silverlight application, you can do the following:

private void DeleteSynchronous(string path)
{
    StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
    Task t = localFolder.DeleteAsync(StorageDeleteOption.PermanentDelete).AsTask();
    t.Wait();
}

private void FunctionThatNeedsToBeSynchronous()
{
    // Do some work here
    // ....

    // Delete something in storage synchronously
    DeleteSynchronous("pathGoesHere");

    // Do other work here 
    // .....
}

Hope this helps!

Foxy
  • 101
  • 1
  • 4
-5

If you want to run it Sync

MethodAsync().RunSynchronously()
smj
  • 416
  • 1
  • 4
  • 10
  • 6
    This method is intended for starting cold tasks. Typically async methods return a hot task, in other words a task that has already started. calling `RunSynchronously()` on a hot task results to an `InvalidOperationException`. Try it with this code: `Task.Run(() => {}).RunSynchronously();` – Theodor Zoulias Apr 29 '19 at 12:07