750

I am learning about async/await, and ran into a situation where I need to call an async method synchronously. How can I do that?

Async method:

public async Task<Customers> GetCustomers()
{
    return await Service.GetCustomersAsync();
}

Normal usage:

public async void GetCustomers()
{
    customerList = await GetCustomers();
}

I've tried using the following:

Task<Customer> task = GetCustomers();
task.Wait()

Task<Customer> task = GetCustomers();
task.RunSynchronously();

Task<Customer> task = GetCustomers();
while(task.Status != TaskStatus.RanToCompletion)

I also tried a suggestion from here, however it doesn't work when the dispatcher is in a suspended state.

public static void WaitWithPumping(this Task task) 
{
        if (task == null) throw new ArgumentNullException(“task”);
        var nestedFrame = new DispatcherFrame();
        task.ContinueWith(_ => nestedFrame.Continue = false);
        Dispatcher.PushFrame(nestedFrame);
        task.Wait();
}

Here is the exception and stack trace from calling RunSynchronously:

System.InvalidOperationException

Message: RunSynchronously may not be called on a task unbound to a delegate.

InnerException: null

Source: mscorlib

StackTrace:

          at System.Threading.Tasks.Task.InternalRunSynchronously(TaskScheduler scheduler)
   at System.Threading.Tasks.Task.RunSynchronously()
   at MyApplication.CustomControls.Controls.MyCustomControl.CreateAvailablePanelList() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 638
   at MyApplication.CustomControls.Controls.MyCustomControl.get_AvailablePanels() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 233
   at MyApplication.CustomControls.Controls.MyCustomControl.<CreateOpenPanelList>b__36(DesktopPanel panel) in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 597
   at System.Collections.Generic.List`1.ForEach(Action`1 action)
   at MyApplication.CustomControls.Controls.MyCustomControl.<CreateOpenPanelList>d__3b.MoveNext() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 625
   at System.Runtime.CompilerServices.TaskAwaiter.<>c__DisplayClass7.<TrySetContinuationForAwait>b__1(Object state)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.Run()
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at System.Windows.Application.Run()
   at MyApplication.App.Main() in C:\Documents and Settings\...\MyApplication\obj\Debug\App.g.cs:line 50
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
John Smith
  • 7,243
  • 6
  • 49
  • 61
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • 52
    The best answer to the question "How can I call an async method synchronously" is "don't". There are [hacks](http://stackoverflow.com/a/5097066/263693) to try to force it to work, but they all have very subtle pitfalls. Instead, back up and fix the code that makes you "need" to do this. – Stephen Cleary Oct 15 '13 at 17:24
  • 91
    @Stephen Cleary Absolutely agree, but sometimes its simply unavoidable, such as when your code is dependent on some 3rd party API that does not use async/await. In addition, if binding to WPF properties when using MVVM, its literally impossible to use async/await as this is not supported on properties. – Contango Sep 12 '14 at 17:43
  • 5
    @StephenCleary Not always. I'm building a DLL which will be imported in [GeneXus](http://www.genexus.com/). It don't support async/await keywords, so I must use only synchronous methods. – Dinei Oct 26 '15 at 13:50
  • @DineiA.Rockenbach: Three better alternatives spring immediately to mind: 1) Have GeneXus add support for async methods; 2) Implement a callback/event instead of using `Task` (often required for cross-language interop); 3) Use synchronous code all the way, so sync-over-async doesn't even come up. Each of these is a better alternative to using dubious hacks. – Stephen Cleary Oct 26 '15 at 13:57
  • 7
    @StephenCleary 1) GeneXus is a 3rd pt tool and I don't have access to its source code; 2) GeneXus don't even has implementations of "functions", so I can't realize how I could implement a "callback" with this type of thing. Surely it would be a harder workaround than using `Task` synchronously; 3) I'm integrating GeneXus with [MongoDB C# driver](https://docs.mongodb.org/getting-started/csharp/), which expose some methods only asynchronously – Dinei Oct 26 '15 at 17:39
  • 8
    @StephenCleary That's all nice theory, but "don't do it" has that inherent issue with it that it "doesn't work". C# actively forbids me to use `await` within synchronised blocks. Should I have Microsoft change their language? Or should I drop my synchronisation and accept messed up data structures? `async` is that cancer, not so much GPL. Once you have it you can't get rid of it. – ygoe Sep 26 '16 at 14:56
  • 2
    @ygoe: Use an async-compatible lock, such as `SemaphoreSlim`. – Stephen Cleary Sep 26 '16 at 19:31
  • 3
    The absence of StackOverflow the biggest names even in late 2016 strongly suggests that there still isn't a simple method to do that. BTW. I wonder why there is no `runsync` operator. – tymtam Nov 19 '16 at 00:32
  • 1
    Possible duplicate of [How to call asynchronous method from synchronous method in C#?](http://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in-c) – Michael Freidgeim Feb 02 '17 at 12:05
  • 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:08
  • @StephenCleary why .net does not provide something like ".RunAsSynchronous()" method that we can call on Task type ? this kind of method would just ignore/remove all that async stuff and run it. So instead of us writing async method and synchronous versions of it, we could just have one metod but caller would decide if they want to use async stuff on it or just completely ignore it as it never existed. – IronHide May 18 '22 at 23:03
  • @IronHide: What about code that returns task objects *not* created by `async`? – Stephen Cleary May 19 '22 at 01:07
  • @StephenCleary I have no idea, I did not think of every possible scenario, I assumed that some async gurus like your self will figure it out in like no time :) (Not being sarcastic) – IronHide May 19 '22 at 05:04
  • 1
    I've been told not to use `var x = SomeAsyncMethod().Result` to run async task inside an non-async method since it will block the main thread and cause deadlock. Is it still valid in 2022 for .NET 6 apps? what if I have that line in a .NET Framework 4.7 project? I've seen people suggest `var x = Task.Run( async ()=> await SomeAsyncMethod()).Result` instead to avoid deadlock. Will that work? – Stack Undefined Sep 06 '22 at 02:54

28 Answers28

535

Here's a workaround I found that works for all cases (including suspended dispatchers). It's not my code and I'm still working to fully understand it, but it does work.

It can be called using:

customerList = AsyncHelpers.RunSync<List<Customer>>(() => GetCustomers());

Code is from here

public static class AsyncHelpers
{
    /// <summary>
    /// Synchronously execute's an async Task method which has a void return value.
    /// </summary>
    /// <param name="task">The Task method to execute.</param>
    public static void RunSync(Func<Task> task)
    {
        var oldContext = SynchronizationContext.Current;
        var syncContext = new ExclusiveSynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(syncContext);
        
        syncContext.Post(async _ =>
        {
            try
            {
                await task();
            }
            catch (Exception e)
            {
                syncContext.InnerException = e;
                throw;
            }
            finally
            {
                syncContext.EndMessageLoop();
            }
        }, null);
        
        syncContext.BeginMessageLoop();

        SynchronizationContext.SetSynchronizationContext(oldContext);
    }

    /// <summary>
    /// Synchronously execute's an async Task<T> method which has a T return type.
    /// </summary>
    /// <typeparam name="T">Return Type</typeparam>
    /// <param name="task">The Task<T> method to execute.</param>
    /// <returns>The result of awaiting the given Task<T>.</returns>
    public static T RunSync<T>(Func<Task<T>> task)
    {
        var oldContext = SynchronizationContext.Current;
        var syncContext = new ExclusiveSynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(syncContext);
        T result;
        
        syncContext.Post(async _ =>
        {
            try
            {
                result = await task();
            }
            catch (Exception e)
            {
                syncContext.InnerException = e;
                throw;
            }
            finally
            {
                syncContext.EndMessageLoop();
            }
        }, null);
        
        syncContext.BeginMessageLoop();
        
        SynchronizationContext.SetSynchronizationContext(oldContext);
        
        return result;
    }

    private class ExclusiveSynchronizationContext : SynchronizationContext
    {
        private readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
        private readonly Queue<Tuple<SendOrPostCallback, object>> items =
            new Queue<Tuple<SendOrPostCallback, object>>();
        private bool done;
        
        public Exception InnerException { get; set; }

        public override void Send(SendOrPostCallback d, object state)
        {
            throw new NotSupportedException("We cannot send to our same thread");
        }

        public override void Post(SendOrPostCallback d, object state)
        {
            lock (items)
            {
                items.Enqueue(Tuple.Create(d, state));
            }
            
            workItemsWaiting.Set();
        }

        public void EndMessageLoop()
        {
            Post(_ => done = true, null);
        }

        public void BeginMessageLoop()
        {
            while (!done)
            {
                Tuple<SendOrPostCallback, object> task = null;
                lock (items)
                {
                    if (items.Count > 0)
                    {
                        task = items.Dequeue();
                    }
                }
                
                if (task != null)
                {
                    task.Item1(task.Item2);
                    if (InnerException != null) // the method threw an exeption
                    {
                        throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
                    }
                }
                else
                {
                    workItemsWaiting.WaitOne();
                }
            }
        }

        public override SynchronizationContext CreateCopy()
        {
            return this;
        }
    }
}
Oliver
  • 9,239
  • 9
  • 69
  • 100
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • 32
    For some background on how this works, Stephen Toub (Mr Parallel) wrote a series of posts about this. [Part 1](http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx) [Part 2](http://blogs.msdn.com/b/pfxteam/archive/2012/01/21/10259307.aspx) [Part 3](http://blogs.msdn.com/b/pfxteam/archive/2012/02/02/10263555.aspx) – Cameron MacFarland Feb 08 '13 at 16:29
  • 18
    I updated John's code to work without wrapping tasks in lambdas: https://github.com/tejacques/AsyncBridge. Essentially you work with async blocks with the using statement. Anything inside a using block happens asynchronously, with a wait at the end. The downside is that you need to unwrap the task yourself in a callback, but it's still fairly elegant, especially if you need to call several async functions at once. – Tom Jacques Jun 25 '13 at 19:47
  • 1
    This method blocks the UI thread it is executed on. Would it be possible to somehow use `Dispatcher.PushFrame(DispatcherFrame)` method to prevent blocking the UI? – ghord Jul 11 '13 at 11:12
  • 3
    @ghord - if you don't want to block the UI then you can't run it synchronously...by definition it will block the thread it runs on. Just await it if you don't want it to block. I don't understand the point of what you are asking. – Mike Marynowski Jul 15 '13 at 17:39
  • @MikeMarynowski I had a problem with async void (cannot change to Task) method with awaits, which I wanted to execute fully before passing control. This solution helps, but it hangs the UI thread, which I was trying to avoid. – ghord Jul 15 '13 at 20:01
  • 1
    What you are asking for is impossible though, just think about it - if you don't pass control back to the UI thread then the UI won't update. By definition, something running synchronously on the UI thread will freeze the UI until it finishes. I'm certain there's a better way to achieve whatever it is you are trying to do. Instead of bloating this thread more, how about you post a separate question and I will try my best to answer it. – Mike Marynowski Jul 16 '13 at 00:14
  • 1
    @MikeMarynowski It was possible in 4.0 with `Dispatcher.PushFrame` and it worked quite well. It just so happens it causes async/await code to deadlock. I don't need new question - I just reorganized my app so it didn't need this. – ghord Jul 17 '13 at 17:10
  • 21
    @StephenCleary Although I generally agree with you that the code should be async all the way down, sometimes you find yourself in an infeasible situation where one *has* to force it as a synchronous call. Basically, my situation is that all my data access code is in async fashion. I needed to build a sitemap based on the sitemap and the third party library I was using was MvcSitemap. Now when one is extending it via the `DynamicNodeProviderBase` base class, one cannot declare it as a `async` method. Either I had to replace with a new library, or just call a synchronous op. – justin.lovell Jan 23 '14 at 06:56
  • 7
    @justin.lovell: Yes, *library limitations* can force us to put in hacks, at least until the library is updated. It sounds like MvcSitemap is one such situation where a hack is required (MVC filters and child actions, too); I just dissuade people from this in general because hacks like this are used way too often when they are *not* necessary. With MVC in particular, some ASP.NET/MVC APIs do assume that they have an `AspNetSynchronizationContext`, so this particular hack won't work if you're calling those APIs. – Stephen Cleary Jan 23 '14 at 12:33
  • 1
    @ghord sure, it still works perfectly: https://gist.github.com/ivan-danilov/3ee430522d596ccf6496 – Ivan Danilov Oct 18 '15 at 23:47
  • 5
    This code will not work. If it is called from a pool thread it can trigger thread-starvation deadlock. Your caller will block waiting for the operation to complete, which may never happen if he has exhausted the thread pool. See [this article](http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx). – ZunTzu Oct 27 '15 at 18:30
  • @Paval This answer is pretty old, however in the past I never had any problems like that with the code. The use of the `await` keyword says *"queue this command on a separate thread, and everything below this to run upon thread completion, then end this code block and go back to whatever else you were doing"*, which in this case is the message loop calling `.WaitOne` repeatedly. Because the task runs on a separate thread, I don't think you should experiencing any dead locks with this code. – Rachel Jul 07 '16 at 15:00
  • 4
    Sometimes you inherit someone else's code that was written all sync, and you have to deliver something by a certain deadline, and rewriting everything to be async upwards isn't an option. – Sentinel Sep 08 '16 at 13:18
  • 3
    This code has a bug. It doesn't restore the old context (`SynchronizationContext.SetSynchronizationContext(oldContext)`) when an exception is thrown. Using `try { ... } finally { ... }` fixes it. – Michael Kropat Oct 05 '16 at 17:27
  • To avoid FxCopy warning Implement IDisposable in ExclusiveSynchronizationContext, disposing _workItemsWaiting – mqueirozcorreia Nov 04 '16 at 23:04
  • 1
    Unfortunately it does not work for *all* cases. WaitOne() internally pumps messages (so that COM things work as expected I believe). This means that external code (such as event handlers) can execute every time a task is awaited in the custom context, and WaitOne() is called. I experienced such a situation causing a deadlock between the main thread and itself :/ I solved it by executing my task on a new thread, and actually blocking with a `while (!task.IsCompleted) { /*wait*/}`. This is ugly, but unless something in your task tries to execute on the waiting thread, everything should work. – Melvyn Feb 21 '18 at 08:40
  • @TomJacques tried your library since I was suspicious of that working without having to wrap in lambdas. Tried with a small winforms app. Didnt work for me. Of course I tested against a hot task. – nawfal Aug 04 '20 at 13:02
  • I am having issues with my console application just hanging, not sure why but after using this code it started happening. – Mike Flynn Oct 11 '20 at 01:36
  • Though this answer has been posted a very long time ago. Thank you so much, after series of searches, this worked once. – Mordecai Mar 11 '21 at 10:25
  • In some rare scenarios the ExclusiveSynchronizationContext.Post() can be called after leaving BeginMessageLoop() and the callback will never be executed. Example: AsyncHelpers.RunSync(() => MyTask()); private static async Task MyTask() { await Task.Delay(1); var scheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task.Run(async () => await Task.Delay(1000)).ContinueWith(g => { Console.WriteLine("Will never be executed"); }, scheduler); await Task.Delay(100); } – Rakoo Jun 23 '21 at 07:57
  • 2
    @cameron macfarland cited a blog post by Stephen Toub. It does not work any more. Has someone an updated link? – JSpot Oct 06 '22 at 10:36
  • See Stephen Toub's blog with [AsyncPump](https://devblogs.microsoft.com/pfxteam/await-synchronizationcontext-and-console-apps/). – JSpot Mar 27 '23 at 10:13
364

Be advised this answer is three years old. I wrote it based mostly on a experience with .Net 4.0, and very little with 4.5 especially with async-await. Generally speaking it's a nice simple solution, but it sometimes breaks things. Please read the discussion in the comments.

.Net 4.5

Just use this:

// For Task<T>: will block until the task is completed...
var result = task.Result; 

// For Task (not Task<T>): will block until the task is completed...
task2.RunSynchronously();

See: TaskAwaiter, Task.Result, Task.RunSynchronously


.Net 4.0

Use this:

var x = (IAsyncResult)task;
task.Start();

x.AsyncWaitHandle.WaitOne();

...or this:

task.Start();
task.Wait();
Rachel
  • 130,264
  • 66
  • 304
  • 490
AK_
  • 7,981
  • 7
  • 46
  • 78
  • If you want to use async in .NET 4.0 you can install the NuGet package async: http://www.nuget.org/packages/Microsoft.Bcl.Async/ – class Jul 24 '13 at 00:00
  • 76
    `.Result` can produce a deadlock in certain scenario's – Jordy Langen Aug 22 '13 at 19:17
  • @JordyLangen of course, you are waiting for that task to complete... But that's usual with parallel programming, and always true when waiting on something... – AK_ Aug 29 '13 at 13:58
  • 137
    `Result` can [easily cause deadlock in `async` code](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html), as I describe on my blog. – Stephen Cleary Sep 05 '13 at 15:58
  • 10
    @StephenCleary I read your post, and tried it myself. I honestly think someone at microsoft was really drunk... It's the same issue as like winforms and background threads.... – AK_ Oct 15 '13 at 16:36
  • 1
    task.Wait() sometimes does not work "synchronously". This introduces some very nasty bugs – Cortlendt Feb 28 '14 at 06:38
  • 12
    The question concerns a Task that is returned by async method. Such kind of Task may have already been started, executed, or canceled, so usage of *Task.RunSynchronously* method may result in *InvalidOperationException*. See MSDN page: [Task.RunSynchronously Method](http://msdn.microsoft.com/en-us/library/dd321435(v=vs.110).aspx). Besides, that Task is probably created by *Task.Factory.StartNew* or *Task.Run* methods (inside async method), so it's dangerous to try start it again. Some race conditions may occur at runtime. In the othe hand, *Task.Wait* and *Task.Result* may result i deadlock. – sgnsajgon Sep 13 '14 at 10:02
  • 6
    Run Synchronously worked for me... I don't know if I'm missing something but this seems preferable to the horrors of the marked answer - I was just looking for a way of switching off async for testing code that just there to stop the ui from hanging – JonnyRaa Sep 25 '14 at 11:17
  • 1
    `Result` causes weird connection exceptions in Entity Framework – Justin Skiles Mar 04 '15 at 03:09
  • 1
    When you run this the following error occurs : RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method. – Mohammad Chamanpara Aug 16 '15 at 13:34
  • The documentation for RunSynchronously() suggests calling Wait() afterword "to handle any exceptions that the task might throw". – blackboxlogic Sep 26 '17 at 15:09
  • 1
    It worth to mention that based on [this](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html#comment-8d8069d0-4401-11e9-ab1b-b1484e5f4180) and [this](https://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html), the deadlock is not a problem for ASP.NET Core! – S.Serpooshan Mar 12 '19 at 05:57
  • 2
    a. RunSynchronously may not be called on a task not bound to a delegate so I wrapped it in a Task(async () => await methodAsync().ConfigureAwait(continueOnCapturedContext: false)) b. Added the .Wait() per the MSDN article Surprise the task started synchronous execution then claimed completion when I/O started, leading to baffling race condition. Fell back to .GetAwaiter().GetResult(); which really waited for completion. By why is RunSynchronously() and Wait() returning before async task is really done??? – David Burg Jun 25 '19 at 04:58
185

Surprised no one mentioned this:

public Task<int> BlahAsync()
{
    // ...
}

int result = BlahAsync().GetAwaiter().GetResult();

Not as pretty as some of the other methods here, but it has the following benefits:

  • it doesn't swallow exceptions (like Wait)
  • it won't wrap any exceptions thrown in an AggregateException (like Result)
  • works for both Task and Task<T> (try it out yourself!)

Also, since GetAwaiter is duck-typed, this should work for any object that is returned from an async method (like ConfiguredAwaitable or YieldAwaitable), not just Tasks.


edit: Please note that it's possible for this approach (or using .Result) to deadlock, unless you make sure to add .ConfigureAwait(false) every time you await, for all async methods that can possibly be reached from BlahAsync() (not just ones it calls directly). Explanation.

// In BlahAsync() body
await FooAsync(); // BAD!
await FooAsync().ConfigureAwait(false); // Good... but make sure FooAsync() and
                                        // all its descendants use ConfigureAwait(false)
                                        // too. Then you can be sure that
                                        // BlahAsync().GetAwaiter().GetResult()
                                        // won't deadlock.

If you're too lazy to add .ConfigureAwait(false) everywhere, and you don't care about performance you can alternatively do

Task.Run(() => BlahAsync()).GetAwaiter().GetResult()
James Ko
  • 32,215
  • 30
  • 128
  • 239
  • 1
    Works for me for simple stuff. Also, if the method returns an IAsyncOperation, I had to convert it to a Task first: BlahAsync().AsTask().GetAwaiter().GetResult(); – Lee McPherson Apr 07 '16 at 05:22
  • 6
    This caused a deadlock inside an asmx web method. Nevertheless, wrapping the method call in a Task.Run() made it work: Task.Run(() => BlahAsync()).GetAwaiter().GetResult() – Augusto Barreto Dec 13 '17 at 14:30
  • 1
    I like this approach best syntactically because it does not involve lambdas. – dythim Jan 30 '18 at 02:19
  • 33
    Please do NOT edit other people's answers to insert a link to your own. If you believe your answer is better, leave it as a comment instead. – Rachel Mar 01 '18 at 21:48
  • Should be a solution for the question as it addresses the problem, minimal custom code, and answer perfectly explains key points. – Eugene Y. Mar 26 '18 at 01:48
  • 1
    https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1.getawaiter?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(System.Threading.Tasks.Task%601.GetAwaiter)%3Bk(TargetFrameworkMoniker-.NETFramework%2CVersion%3Dv4.6.1)%3Bk(DevLang-csharp)%26rd%3Dtrue&view=netframework-4.6.2#remarks says about `GetAwaiter()`, "This method is intended for compiler user rather than use directly in code." – Mike Grove aka Theophilus Sep 04 '19 at 17:04
  • This way (BlahAsync()).GetAwaiter().GetResult()) can cause the program to stall and never finish. This is why I had to switch to Rachel's for much better performance. – DotNet Programmer Feb 19 '20 at 17:30
  • much cleaner than accepted, thanks, should remembered :D – alexDuty Apr 19 '23 at 13:09
81

It's much simpler to run the task on the thread pool, rather than trying to trick the scheduler to run it synchronously. That way you can be sure that it won't deadlock. Performance is affected because of the context switch.

Task<MyResult> DoSomethingAsync() { ... }

// Starts the asynchronous task on a thread-pool thread.
// Returns a proxy to the original task.
Task<MyResult> task = Task.Run(() => DoSomethingAsync());

// Will block until the task is completed...
MyResult result = task.Result; 
Michael L Perry
  • 7,327
  • 3
  • 35
  • 34
  • And if the task is void (without result)? – J. Lennon Oct 06 '13 at 23:17
  • 3
    Then you call task.Wait(). The data type is simply Task. – Michael L Perry Apr 09 '14 at 14:51
  • 1
    Let's assume that *DoSomethingAsync()* is long-running async method as whole (internally it awaits a long-running task), but it yields back a flow control to its caller quickly, thus the lambda argument work ends also quickly. The result of Tusk.Run() may *Task* or *Task>*, so you are awaiting a result of outer task which is completed quickly, but inner task ( due to awaiting long-running job in async method) is still running. Conclusions are that we probably need to use *Unwrap()* approach (as was done in @J.Lennon post) to achieve synchronous behaviour of async method. – sgnsajgon Sep 13 '14 at 09:33
  • 5
    @sgnsajgon You are wrong. Task.Run is different than Task.Factory.StartNew in that it automatically unwraps the result already. See [this article](http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx). – ZunTzu Nov 02 '15 at 09:36
  • 1
    Can I just write `Task.Run(DoSomethingAsync)` instead? This removes one level of delegates. – ygoe Dec 13 '17 at 16:36
  • 1
    Yep. Going the opposite direction, though, as in `Task task = Task.Run(async () => await DoSomethingAsync());` is more explicit and addresses the concern by @sgnsajgon that it might be returning a Task>. The correct overload of Task.Run is selected either way, but the async delegate makes your intent obvious. – Michael L Perry Feb 20 '18 at 22:17
73

I'm learning about async/await, and ran into a situation where I need to call an async method synchronously. How can I do that?

The best answer is you don't, with the details dependent on what the "situation" is.

Is it a property getter/setter? In most cases, it's better to have asynchronous methods than "asynchronous properties". (For more info, see my blog post on asynchronous properties).

Is this an MVVM app and you want to do asynchronous data binding? Then use something like my NotifyTask, as described in my MSDN article on asynchronous data binding.

Is it a constructor? Then you probably want to consider an asynchronous factory method. (For more info, see my blog post on asynchronous constructors).

There's almost always a better answer than to do sync-over-async.

If it's not possible for your situation (and you know this by asking a question here describing the situation), then I'd recommend just using synchronous code. Async all the way is best; sync all the way is second-best. Sync-over-async is not recommended.

However, there are a handful of situations where sync-over-async is necessary. Specifically, you are constrained by the calling code so that you have to be sync (and have absolutely no way to re-think or re-structure your code to allow asynchrony), and you have to call async code. This is a very rare situation, but it does come up from time to time.

In that case, you would need to use one of the hacks described in my article on brownfield async development, specifically:

  • Blocking (e.g., GetAwaiter().GetResult()). Note that this can cause deadlocks (as I describe on my blog).
  • Running the code on a thread pool thread (e.g., Task.Run(..).GetAwaiter().GetResult()). Note that this will only work if the asynchronous code can be run on a thread pool thread (i.e., is not dependent on a UI or ASP.NET context).
  • Nested message loops. Note that this will only work if the asynchronous code only assumes a single-threaded context, not a specific context type (a lot of UI and ASP.NET code expect a specific context).

Nested message loops are the most dangerous of all the hacks, because it causes re-entrancy. Re-entrancy is extremely tricky to reason about, and (IMO) is the cause of most application bugs on Windows. In particular, if you're on the UI thread and you block on a work queue (waiting for the async work to complete), then the CLR actually does some message pumping for you - it'll actually handle some Win32 messages from within your code. Oh, and you have no idea which messages - when Chris Brumme says "Wouldn’t it be great to know exactly what will get pumped? Unfortunately, pumping is a black art which is beyond mortal comprehension.", then we really have no hope of knowing.

So, when you block like this on a UI thread, you're asking for trouble. Another cbrumme quote from the same article: "From time to time, customers inside or outside the company discover that we are pumping messages during managed blocking on an STA [UI thread]. This is a legitimate concern, because they know that it’s very hard to write code that’s robust in the face of reentrancy."

Yes, it is. Very hard to write code that's robust in the face of reentrancy. And nested message loops force you to write code that's robust in the face of reentrancy. This is why the accepted (and most-upvoted) answer for this question is extremely dangerous in practice.

If you are completely out of all other options - you can't redesign your code, you can't restructure it to be async - you are forced by unchangeable calling code to be sync - you can't change the downstream code to be sync - you can't block - you can't run the async code on a separate thread - then and only then should you consider embracing reentrancy.

If you do find yourself in this corner, I would recommend using something like Dispatcher.PushFrame for WPF apps, looping with Application.DoEvents for WinForm apps, and for the general case, my own AsyncContext.Run.

Community
  • 1
  • 1
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Stephen, there is another very similar [qestion](http://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in-c) which you provided awesome answer too. Do you think one of them can be closed as duplicate or maybe merge request or bring up on meta first (as each q has ~200K views 200+ votes)? Suggestions? – Alexei Levenkov Feb 05 '17 at 08:05
  • 2
    @AlexeiLevenkov: I don't feel right doing that, for a few reasons: 1) The answer on the linked question is fairly out-of-date. 2) I've written an [entire article on the subject](https://msdn.microsoft.com/en-us/magazine/mt238404.aspx) that I feel is more complete than any existing SO Q/A. 3) The accepted answer on this question is *extremely* popular. 4) I am *vehemently* opposed to that accepted answer. So, closing this as a dup of that would be an abuse of power; closing that as a dup of this (or merging) would empower a dangerous answer even more. I let it be, and leave it to the community. – Stephen Cleary Feb 05 '17 at 14:15
  • Ok. I'll consider bringing it up on meta than in some way. – Alexei Levenkov Feb 06 '17 at 18:14
  • 14
    This answer goes a long way over my head. *"Use async all the way down"* is confusing advice, due to clearly not being possible to follow. A program with an async `Main()` method doesn't compile; at some point you've *got* to bridge the gap between the sync and async worlds. It's not a *"**very** rare situation"*, it's necessary in literally every program that calls an async method. There is no option to not *"do sync-over-async"*, just an option to shunt that burden up to the calling method instead of shouldering it in the one you're currently writing. – Mark Amery Jun 13 '17 at 13:20
  • 3
    @MarkAmery: Sync-over-async is necessary in the `Main` method of console apps. ASP.NET, unit test frameworks, and every UI system all support async natively. Even if all your apps are console apps, you'd only need to do sync-over-async once per app. (of course, library callbacks that don't support async yet may require additional hacks). – Stephen Cleary Jun 13 '17 at 14:41
  • 1
    Great. I'm about to put `async` on all of the methods in my application now. And that's a lot. Can't this just be the default? – ygoe Dec 13 '17 at 16:53
  • 1
    It worth to mention that as you [replied me](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html#comment-8d8069d0-4401-11e9-ab1b-b1484e5f4180) and based on your blog [here](https://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html), the deadlock is not a problem for ASP.NET Core! – S.Serpooshan Mar 12 '19 at 05:54
26

If I am reading your question right - the code that wants the synchronous call to an async method is executing on a suspended dispatcher thread. And you want to actually synchronously block that thread until the async method is completed.

Async methods in C# 5 are powered by effectively chopping the method into pieces under the hood, and returning a Task that can track the overall completion of the whole shabang. However, how the chopped up methods execute can depend on the type of the expression passed to the await operator.

Most of the time, you'll be using await on an expression of type Task. Task's implementation of the await pattern is "smart" in that it defers to the SynchronizationContext, which basically causes the following to happen:

  1. If the thread entering the await is on a Dispatcher or WinForms message loop thread, it ensures that the chunks of the async method occurs as part of the processing of the message queue.
  2. If the thread entering the await is on a thread pool thread, then the remaining chunks of the async method occur anywhere on the thread pool.

That's why you're probably running into problems - the async method implementation is trying to run the rest on the Dispatcher - even though it's suspended.

.... backing up! ....

I have to ask the question, why are you trying to synchronously block on an async method? Doing so would defeat the purpose on why the method wanted to be called asynchronously. In general, when you start using await on a Dispatcher or UI method, you will want to turn your entire UI flow async. For example, if your callstack was something like the following:

  1. [Top] WebRequest.GetResponse()
  2. YourCode.HelperMethod()
  3. YourCode.AnotherMethod()
  4. YourCode.EventHandlerMethod()
  5. [UI Code].Plumbing() - WPF or WinForms Code
  6. [Message Loop] - WPF or WinForms Message Loop

Then once the code has been transformed to use async, you'll typically end up with

  1. [Top] WebRequest.GetResponseAsync()
  2. YourCode.HelperMethodAsync()
  3. YourCode.AnotherMethodAsync()
  4. YourCode.EventHandlerMethodAsync()
  5. [UI Code].Plumbing() - WPF or WinForms Code
  6. [Message Loop] - WPF or WinForms Message Loop

Actually Answering

The AsyncHelpers class above actually works because it behaves like a nested message loop, but it installs its own parallel mechanic to the Dispatcher rather than trying to execute on the Dispatcher itself. That's one workaround for your problem.

Another workaround is to execute your async method on a threadpool thread, and then wait for it to complete. Doing so is easy - you can do it with the following snippet:

var customerList = TaskEx.RunEx(GetCustomers).Result;

The final API will be Task.Run(...), but with the CTP you'll need the Ex suffixes (explanation here).

Morse
  • 8,258
  • 7
  • 39
  • 64
Theo Yaung
  • 3,994
  • 1
  • 18
  • 14
  • +1 for the detailed explanation, however `TaskEx.RunEx(GetCustomers).Result` hangs the application when it gets run on a suspended dispatcher thread. Also, the GetCustomers() method is normally run async, however in one situation it needs to run synchronously, so I was looking for a way to do that without building a sync version of the method. – Rachel Feb 25 '11 at 14:39
  • +1 for "why are you trying to synchronously block on an async method?" There is always a way to properly use `async` methods; nested loops should certainly be avoided. – Stephen Cleary Sep 05 '13 at 15:59
25

This is working well for me

public static class TaskHelper
{
    public static void RunTaskSynchronously(this Task t)
    {
        var task = Task.Run(async () => await t);
        task.Wait();
    }

    public static T RunTaskSynchronously<T>(this Task<T> t)
    {
        T res = default(T);
        var task = Task.Run(async () => res = await t);
        task.Wait();
        return res;
    }
}
Clement
  • 3,990
  • 4
  • 43
  • 44
  • You need to also use *Task.Unwrap* method, because your *Task.Wait* statement causes waiting for outer Task (created by *Task.Run*), not for inner *await t* Task passed as parameter of extension method. Your *Task.Run* method returns not Task, but Task>. In some simple scenarios your solution may works because of TaskScheduler optimizations, for example using *TryExecuteTaskInline* method to execute Tasks within current thread during *Wait* operation .Please look at my comment to [this](http://stackoverflow.com/a/17094801/823040) answer. – sgnsajgon Sep 15 '14 at 18:45
  • 1
    That is not correct. The Task.Run will return Task. See this overload http://msdn.microsoft.com/en-us/library/hh194918(v=vs.110).aspx – Clement Sep 15 '14 at 23:02
  • 1
    How is this supposed to be used? This deadlocks in WPF: `MyAsyncMethod().RunTaskSynchronously();` – ygoe Sep 26 '16 at 15:20
  • 1
    This only works for platforms without synchronization contexts (console apps, ASP.NET Core apps etc). For platforms with sync context, this work for only cold tasks, aka not the 99% normal cases. For tasks that has already started, there is no point in wrapping it in `Task.Run`. In other words, in normal usages like `GetFromNetworkAsync().RunTaskSynchronously()` hangs for UI apps. – nawfal Aug 04 '20 at 04:16
23

Tested in .Net 4.6. It can also avoid deadlock.

For async method returning Task.

Task DoSomeWork();
Task.Run(async () => await DoSomeWork()).Wait();

For async method returning Task<T>

Task<T> GetSomeValue();
var result = Task.Run(() => GetSomeValue()).Result;

Edit:

If the caller is running in the thread pool thread (or the caller is also in a task), it may still cause a deadlock in some situation.

Palle Due
  • 5,929
  • 4
  • 17
  • 32
Liang
  • 867
  • 11
  • 13
  • 2
    My answar after almost 8 years :) The second example - will produce a deadlock in all scheduled context that are mainly used (console app / .NET core / desktop app / ...). here you have more overview what i'm talking about now: https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d – Marek Woźniak Feb 14 '19 at 13:57
  • `Result` is perfect for the job if you want a synchronous call, and downright dangerous otherwise. There is nothing in the name `Result` or in the intellisense of `Result` that indicates it is a blocking call. It really should be renamed. – Zodman Apr 24 '20 at 04:40
17

I've faced it a few times, mostly in unit testing or in a windows service development. Currently I always use this feature:

        var runSync = Task.Factory.StartNew(new Func<Task>(async () =>
        {
            Trace.WriteLine("Task runSync Start");
            await TaskEx.Delay(2000); // Simulates a method that returns a task and
                                      // inside it is possible that there
                                      // async keywords or anothers tasks
            Trace.WriteLine("Task runSync Completed");
        })).Unwrap();
        Trace.WriteLine("Before runSync Wait");
        runSync.Wait();
        Trace.WriteLine("After runSync Waited");

It's simple, easy and I had no problems.

J. Lennon
  • 3,311
  • 4
  • 33
  • 64
17

I found this code at Microsoft.AspNet.Identity.Core component, and it works.

private static readonly TaskFactory _myTaskFactory = new 
     TaskFactory(CancellationToken.None, TaskCreationOptions.None, 
     TaskContinuationOptions.None, TaskScheduler.Default);

// Microsoft.AspNet.Identity.AsyncHelper
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
    CultureInfo cultureUi = CultureInfo.CurrentUICulture;
    CultureInfo culture = CultureInfo.CurrentCulture;
    return AsyncHelper._myTaskFactory.StartNew<Task<TResult>>(delegate
    {
        Thread.CurrentThread.CurrentCulture = culture;
        Thread.CurrentThread.CurrentUICulture = cultureUi;
        return func();
    }).Unwrap<TResult>().GetAwaiter().GetResult();
}
wenhx
  • 245
  • 2
  • 8
16

The simplest way I have found to run task synchronously and without blocking UI thread is to use RunSynchronously() like:

Task t = new Task(() => 
{ 
   //.... YOUR CODE ....
});
t.RunSynchronously();

In my case, I have an event that fires when something occurs. I dont know how many times it will occur. So, I use code above in my event, so whenever it fires, it creates a task. Tasks are executed synchronously and it works great for me. I was just surprised that it took me so long to find out of this considering how simple it is. Usually, recommendations are much more complex and error prone. This was it is simple and clean.

pixel
  • 9,653
  • 16
  • 82
  • 149
  • 1
    But how could we use this method when the async code returns something we need? – S.Serpooshan Sep 10 '18 at 09:07
  • 1
    This works for cold tasks, not tasks that has begun. – nawfal Aug 04 '20 at 12:20
  • This will not work because "YOUR CODE" in your example must be synchronous code for this Task constructor. But we actually have async code we would want to put there. – JSpot Oct 06 '22 at 10:29
14

Just a little note - this approach:

Task<Customer> task = GetCustomers();
task.Wait()

works for WinRT.

Let me explain:

private void TestMethod()
{
    Task<Customer> task = GetCustomers(); // call async method as sync and get task as result
    task.Wait(); // wait executing the method
    var customer = task.Result; // get's result.
    Debug.WriteLine(customer.Name); //print customer name
}
public class Customer
{
    public Customer()
    {
        new ManualResetEvent(false).WaitOne(TimeSpan.FromSeconds(5));//wait 5 second (long term operation)
    }
    public string Name { get; set; }
}
private Task<Customer> GetCustomers()
{
    return Task.Run(() => new Customer
    {
        Name = "MyName"
    });
}

Moreover this approach works for Windows Store solutions only!

Note: This way isn't thread safe if you call your method inside of other async method (according to comments of @Servy)

animuson
  • 53,861
  • 28
  • 137
  • 147
RredCat
  • 5,259
  • 5
  • 60
  • 100
  • I explained this solution, check EDIT section. – RredCat Dec 16 '13 at 19:01
  • 2
    This can very easily result in deadlocks when called in asynchronous situations. – Servy Dec 16 '13 at 19:07
  • @Servy make sense. So as I get correct using Wait(timeOut) can help, right? – RredCat Dec 16 '13 at 20:49
  • 1
    Then you need to worry about having the timeout being reached when the operation isn't actually done, which is very bad, and also the time spent waiting until the timeout in the cases where it deadlocks (and in that case you're *still* continuing on when it's not done). So no, that doesn't fix the problem. – Servy Dec 16 '13 at 20:50
  • @Servy Looks like I have to implement `CancellationToken` for my solution. – RredCat Dec 16 '13 at 21:41
  • @Servy Why, could you explain a bit? – RredCat Dec 16 '13 at 21:47
  • I could, or you could just ask Google about it, or for that matter just look at the comments on the answers that are, more or less, a duplicate of yours; in particular the one with the most votes, as it has [a link to] an explanation. – Servy Dec 16 '13 at 21:49
  • Your example works because your *GetCustomers()* method is not the *async* method in terms of C# 5.0 (no *async-await* keywords pair), but just a *Task-returning* method. The question was about C# 5.0 *async* method. Mark your *GetCustomers()* method as *async*, then *await Task.Run()* invocation, then you will probably get deadlock. – sgnsajgon Sep 13 '14 at 10:33
9

NOTE: I think as best practice is not recommended to change the nature of the action if it is asynchronous the best thing is handling as it is (async all the way). In that way you can get other benefits like parallel processing / multi-threading, etc.

Seeing the other answers did not use this approach, I want to post it here as well:

var customers = GetCustomersAsync().GetAwaiter().GetResult();
Jaider
  • 14,268
  • 5
  • 75
  • 82
  • 1
    This is still equivalent to calling `var customer = GetCustomersAsync().Result` but now exceptions are unwrapped instead of being wrapped inside an AggregatedException. – Stack Undefined Sep 06 '22 at 03:19
8

In your code, your first wait for task to execute but you haven't started it so it waits indefinitely. Try this:

Task<Customer> task = GetCustomers();
task.RunSynchronously();

Edit:

You say that you get an exception. Please post more details, including stack trace.
Mono contains the following test case:

[Test]
public void ExecuteSynchronouslyTest ()
{
        var val = 0;
        Task t = new Task (() => { Thread.Sleep (100); val = 1; });
        t.RunSynchronously ();

        Assert.AreEqual (1, val);
}

Check if this works for you. If it does not, though very unlikely, you might have some odd build of Async CTP. If it does work, you might want to examine what exactly the compiler generates and how Task instantiation is different from this sample.

Edit #2:

I checked with Reflector that the exception you described occurs when m_action is null. This is kinda odd, but I'm no expert on Async CTP. As I said, you should decompile your code and see how exactly Task is being instantiated any how come its m_action is null.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
  • I adjusted my question to make the code I had attempted a bit clearer. RunSynchronously returns an error of `RunSynchronously may not be called on a task unbound to a delegate`. Google is no help since all the results for that are in chinese... – Rachel Feb 23 '11 at 18:51
  • I think the difference is that I don't create the Task and then try to run it. Instead, the task is created by the async method when the `await` keyword is used. The exception posted in my earlier comment is the exception I get, although it is one of the few that I cannot Google and find a cause or resolution for. – Rachel Feb 23 '11 at 19:40
  • 1
    `async` and `async` keywords are nothing more than syntax sugar. Compiler generates code to create `Task` in `GetCustomers()` so that's where I would look first. As for exception, you only posted exception message, which is useless without exception type and stack trace. Call exception's `ToString()` method and post output in the question. – Dan Abramov Feb 23 '11 at 19:44
  • @gaearon: I posted the exception details and stack trace in my original question. – Rachel Feb 23 '11 at 20:00
  • I'm also wondering if you're using `Task` from .NET 4.0 (not some preview release) and stable version of Async CTP. – Dan Abramov Feb 23 '11 at 20:27
  • I'm using the most stable release of AsyncCTP as of a month or two ago, and the .Net 4.0 Task object. I actually found an alternative that works, although its not my code so I'm still working to fully understand it. – Rachel Feb 23 '11 at 20:59
  • 4
    @gaearon I think you had got downvotes because your post is not applicable to question. The discussion is about async-await methods, not about simple Task-returning methods. Moreover, in my opinion, async-await mechanism is a syntax sugar, but not so trivial - there is continuation , context capturing, local context resuming, enhanced local exceptions handling, and more. Then, you shouldn't invoke *RunSynchronously* method on result of the async method, because by definition asynchronous method should return Task that is currently at least scheduled, and more than once is in the running state. – sgnsajgon Sep 15 '14 at 19:01
6

Why not create a call like:

Service.GetCustomers();

that isn't async.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
3

This answer is designed for anyone who is using WPF for .NET 4.5.

If you attempt to execute Task.Run() on the GUI thread, then task.Wait() will hang indefinitely, if you do not have the async keyword in your function definition.

This extension method solves the problem by checking to see if we are on the GUI thread, and if so, running the task on the WPF dispatcher thread.

This class can act as the glue between the async/await world and the non-async/await world, in situations where it is unavoidable, such as MVVM properties or dependencies on other APIs that do not use async/await.

/// <summary>
///     Intent: runs an async/await task synchronously. Designed for use with WPF.
///     Normally, under WPF, if task.Wait() is executed on the GUI thread without async
///     in the function signature, it will hang with a threading deadlock, this class 
///     solves that problem.
/// </summary>
public static class TaskHelper
{
    public static void MyRunTaskSynchronously(this Task task)
    {
        if (MyIfWpfDispatcherThread)
        {
            var result = Dispatcher.CurrentDispatcher.InvokeAsync(async () => { await task; });
            result.Wait();
            if (result.Status != DispatcherOperationStatus.Completed)
            {
                throw new Exception("Error E99213. Task did not run to completion.");
            }
        }
        else
        {
            task.Wait();
            if (task.Status != TaskStatus.RanToCompletion)
            {
                throw new Exception("Error E33213. Task did not run to completion.");
            }
        }
    }

    public static T MyRunTaskSynchronously<T>(this Task<T> task)
    {       
        if (MyIfWpfDispatcherThread)
        {
            T res = default(T);
            var result = Dispatcher.CurrentDispatcher.InvokeAsync(async () => { res = await task; });
            result.Wait();
            if (result.Status != DispatcherOperationStatus.Completed)
            {
                throw new Exception("Error E89213. Task did not run to completion.");
            }
            return res;
        }
        else
        {
            T res = default(T);
            var result = Task.Run(async () => res = await task);
            result.Wait();
            if (result.Status != TaskStatus.RanToCompletion)
            {
                throw new Exception("Error E12823. Task did not run to completion.");
            }
            return res;
        }
    }

    /// <summary>
    ///     If the task is running on the WPF dispatcher thread.
    /// </summary>
    public static bool MyIfWpfDispatcherThread
    {
        get
        {
            return Application.Current.Dispatcher.CheckAccess();
        }
    }
}
Contango
  • 76,540
  • 58
  • 260
  • 305
3

use below code snip

Task.WaitAll(Task.Run(async () => await service.myAsyncMethod()));
Mahesh
  • 2,731
  • 2
  • 32
  • 31
3

Simply calling .Result; or .Wait() is a risk for deadlocks as many have said in comments. Since most of us like oneliners you can use these for .Net 4.5<

Acquiring a value via an async method:

var result = Task.Run(() => asyncGetValue()).Result;

Syncronously calling an async method

Task.Run(() => asyncMethod()).Wait();

No deadlock issues will occur due to the use of Task.Run.

Source:

https://stackoverflow.com/a/32429753/3850405

Ogglas
  • 62,132
  • 37
  • 328
  • 418
2

I think the following helper method could also solve the problem.

private TResult InvokeAsyncFuncSynchronously<TResult>(Func< Task<TResult>> func)
    {
        TResult result = default(TResult);
        var autoResetEvent = new AutoResetEvent(false);

        Task.Run(async () =>
        {
            try
            {
                result = await func();
            }
            catch (Exception exc)
            {
                mErrorLogger.LogError(exc.ToString());
            }
            finally
            {
                autoResetEvent.Set();
            }
        });
        autoResetEvent.WaitOne();

        return result;
    }

Can be used the following way:

InvokeAsyncFuncSynchronously(Service.GetCustomersAsync);
donttellya
  • 452
  • 1
  • 3
  • 13
  • It is not an true "synchronously".Y ou create two threads and wait in first results of other. – tmt May 18 '16 at 14:02
  • and all things aside, this is a very bad idea. – Dan Sep 13 '16 at 10:22
  • 1
    I just wrote almost the identical code (line by line the same) but instead using SemaphoreSlim instead of the auto reset event. Wish I had seen this sooner. I find this approach to prevent deadlocks and keeps your async code running the same as it does in true asynchronous scenarios. Not really sure why this is a bad idea. Seems much cleaner than the other approaches I have seen above. – tmrog Jun 20 '17 at 12:12
  • @DanPantry I am actually seeing some deadlocks now with this approach that I don't understand. Could you expand on why it is a bad idea? – tmrog Jun 20 '17 at 12:32
  • My bad. I got. this working now. My problem was that I was creating the task on the main thread and then passed that task to the invoke async method. Thanks @donttellya your code helped me out. – tmrog Jun 20 '17 at 13:20
1

This is works for me

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    public static class AsyncHelper
    {
        private static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);

        public static void RunSync(Func<Task> func)
        {
            _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
        }

        public static TResult RunSync<TResult>(Func<Task<TResult>> func)
        {
            return _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
        }
    }

    class SomeClass
    {
        public async Task<object> LoginAsync(object loginInfo)
        {
            return await Task.FromResult(0);
        }
        public object Login(object loginInfo)
        {
            return AsyncHelper.RunSync(() => LoginAsync(loginInfo));
            //return this.LoginAsync(loginInfo).Result.Content;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var someClass = new SomeClass();

            Console.WriteLine(someClass.Login(1));
            Console.ReadLine();
        }
    }
}
Dan Nguyen
  • 1,308
  • 6
  • 17
0

Async method:

public async Task<Customers> GetCustomers()
{
    return await Service.GetCustomersAsync();
}

This seems to work for me:

Task.Run(GetCustomers).Wait();
Noob
  • 710
  • 11
  • 15
-1

Executing an async task from synchronous code poses a few rather big challenges in conventional .NET:

  • The wait operation for an async task is prone to deadlocks unless a proper synchronization context is in place
  • The cancellation models of sync and async code may be different and incompatible

I really think we should have this interoperability functionality in .NET BCL. Meanwhile, you can use TaskBridge class from Gapotchenko.FX.Threading NuGet package. It provides seamless interoperability between synchronous and asynchronous code execution models:

using Gapotchenko.FX.Threading.Tasks;
using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        TaskBridge.Execute(RunAsync);
    }

    static async Task RunAsync()
    {
        await Console.Out.WriteLineAsync("Hello, Async World!");
    }
}

The NuGet package with TaskBridge class is available here.


Cancellation Models

TaskBridge provides automatic interoperability between different cancellation models.

Let's call a cancelable async method from a synchronous thread that can be aborted by Thread.Abort() method:

void SyncMethod() // can be canceled by Thread.Abort()
{
    // Executes an async task that is gracefully canceled via cancellation
    // token when current thread is being aborted or interrupted.
    TaskBridge.Execute(DoJobAsync); // <-- TaskBridge DOES THE MAGIC
}

async Task DoJobAsync(CancellationToken ct)
{
    …
    // Gracefully handles cancellation opportunities.
    ct.ThrowIfCancellationRequested();
    …
}

Now, let's take a look at the opposite scenario where a cancelable async task calls an abortable synchronous code:

async Task DoJobAsync(CancellationToken ct) // can be canceled by a specified cancellation token
{
    // Executes a synchronous method that is thread-aborted when
    // a specified cancellation token is being canceled.
    await TaskBridge.ExecuteAsync(SyncMethod, ct); // <-- TaskBridge DOES THE MAGIC
}

void SyncMethod()
{
    …
}

The code above demonstrates a simple one-liner for a complete interoperability between the two execution models.

Note: the newer versions of .NET starting with .NET Core do not support Thread.Abort(). This is not a big deal because you can just pass a cancellation token to the cancellable methods instead.

ogggre
  • 2,204
  • 1
  • 23
  • 19
  • I would rather not install another nuget package. Is there any way to avoid the deadlock and still run an async task inside a non-async method? I've come across this `var x = Task.Run( async () => await SomeAsyncMethod() ).Result` as an alternative for the blocking situation. I'm not sure if it actually works. – Stack Undefined Sep 06 '22 at 03:17
  • There is no way to reliably do that without a substantial amount of additional code. It would be great to have it in BCL out of the box; but for now there is a package to not reinvent the wheel every other time. – ogggre Sep 06 '22 at 11:51
  • @StackUndefined The piece of code suggested by you is a workaround. It gets away by totally isolating the async task from the synchronization context by producing one more thread which wouldn't be needed if a more efficient solution was in place. There are some gotchas in exception propagation as well, so you better be using `.GetAwaiter().GetResult()` instead of `.Result` to preserve the original exception intact. – ogggre Sep 06 '22 at 12:07
  • Thanks for the `.GetAwaiter().GetResult()` suggestion. The `.Result` will swallow the exceptions and throw the `AggregateException`. – Stack Undefined Sep 06 '22 at 12:28
-2

I know this is an old Question, but i'll like to share my solution, may not be the best but does the job:

//Declare an Event Handler:
private event EventHandler OnThemeApply;

//..somewhere in your code..

//we 'hear' the event handler
this.OnThemeApply += (object _Sender, EventArgs _E) =>
{
  //Reaches here After the Async method had finished
  
  this.OnThemeApply = null;
};
MyAsycMethod();

private void MyAsycMethod()
{
   var t = System.Threading.Tasks.Task.Factory.StartNew(delegate
   {
      //Do something here

      Invoke((MethodInvoker)(() =>
      {
         if(this.OnThemeApply != null) this.OnThemeApply(null, null); //<- Calls the Event
      }));
   });
}
Jhollman
  • 2,093
  • 24
  • 19
-3

On wp8:

Wrap it:

Task GetCustomersSynchronously()
{
    Task t = new Task(async () =>
    {
        myCustomers = await GetCustomers();
    }
    t.RunSynchronously();
}

Call it:

GetCustomersSynchronously();
  • 3
    Nope, this wont work, because the task does not await the delegate from the constructor (its a delegate and not a task..) – Rico Suter Jul 29 '13 at 11:09
-3

I have found that SpinWait works pretty well for this.

var task = Task.Run(()=>DoSomethingAsyncronous());

if(!SpinWait.SpinUntil(()=>task.IsComplete, TimeSpan.FromSeconds(30)))
{//Task didn't complete within 30 seconds, fail...
   return false;
}

return true;

The above approach doesn't need to use .Result or .Wait(). It also lets you specify a timeout so that you're not stuck forever in case the task never completes.

Curtis
  • 5,794
  • 8
  • 50
  • 77
  • 1
    This is polling (spinning), the delegate will be taking thread from pool up to 1000 times per second. It may not return control immediately after task is finished (up to [10+ms](https://referencesource.microsoft.com/#mscorlib/system/threading/SpinWait.cs,120) error). If finished by timeout the task will continues running, which makes timeout practically useless. – Sinatr May 20 '19 at 07:59
  • Actually, I'm using this all over the place in my code and when the condition is met, SpinWaitSpinUntil() immediately exits. So whichever comes first, 'condition met' or timeout, the task exits. It does not continue to run. – Curtis May 22 '19 at 20:45
-4
    private int GetSync()
    {
        try
        {
            ManualResetEvent mre = new ManualResetEvent(false);
            int result = null;

            Parallel.Invoke(async () =>
            {
                result = await SomeCalcAsync(5+5);
                mre.Set();
            });

            mre.WaitOne();
            return result;
        }
        catch (Exception)
        {
            return null;
        }
    }
-6

Or you could just go with:

customerList = Task.Run<List<Customer>>(() => { return GetCustomers(); }).Result;

For this to compile make sure you reference extension assembly:

System.Net.Http.Formatting
thor
  • 21,418
  • 31
  • 87
  • 173
-9

Try following code it works for me:

public async void TaskSearchOnTaskList (SearchModel searchModel)
{
    try
    {
        List<EventsTasksModel> taskSearchList = await Task.Run(
            () => MakeasyncSearchRequest(searchModel),
            cancelTaskSearchToken.Token);

        if (cancelTaskSearchToken.IsCancellationRequested
                || string.IsNullOrEmpty(rid_agendaview_search_eventsbox.Text))
        {
            return;
        }

        if (taskSearchList == null || taskSearchList[0].result == Constants.ZERO)
        {
            RunOnUiThread(() => {
                textViewNoMembers.Visibility = ViewStates.Visible;                  
                taskListView.Visibility = ViewStates.Gone;
            });

            taskSearchRecureList = null;

            return;
        }
        else
        {
            taskSearchRecureList = TaskFooterServiceLayer
                                       .GetRecurringEvent(taskSearchList);

            this.SetOnAdapter(taskSearchRecureList);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("ActivityTaskFooter -> TaskSearchOnTaskList:" + ex.Message);
    }
}
Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47