281

I have an async method:

public async Task<string> GenerateCodeAsync()
{
    string code = await GenerateCodeService.GenerateCodeAsync();
    return code;
}

I need to call this method from a synchronous method.

How can I do this without having to duplicate the GenerateCodeAsync method in order for this to work synchronously?

Update

Yet no reasonable solution found.

However, I see that HttpClient already implements this pattern

using (HttpClient client = new HttpClient())
{
    // async
    HttpResponseMessage responseAsync = await client.GetAsync(url);

    // sync
    HttpResponseMessage responseSync = client.GetAsync(url).Result;
}
Dale K
  • 25,246
  • 15
  • 42
  • 71
Catalin
  • 11,503
  • 19
  • 74
  • 147
  • 3
    possible duplicate of [How would I run an async Task method synchronously?](http://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously) – Heinzi Mar 25 '14 at 07:37
  • 2
    I was hoping for a simpler solution, thinking that asp.net handled this much easier than writing so many lines of code – Catalin Mar 25 '14 at 07:46
  • Why don't just embrace async code? Ideally you'd want more async code, not less. – Paulo Morgado Mar 26 '14 at 10:02
  • 74
    [Why don't just embrace async code?] Ha, it may be precisely because one is embracing async code that they need this solution as large parts of the project get converted! You cannot rebuild Rome in a day. – Nicholas Petersen Dec 17 '14 at 19:38
  • Well, next step. I need to be able to kill thread, running my synchronous method so GenerateCodeAsync must be killed too – dimzon Oct 12 '15 at 12:50
  • The answers given here are incorrect. You can still deadlock on .Result, even if you schedule on the thread pool, because you yourself can be running on the threadpool. It really boils down to mixing async + synchronous code is a really bad idea. If possible, consider making the root async and wrapping your long-running synchronous work either with the long running flag or a TaskCompletionSource and your own worker threads that process a queue and signal completion. – Warty Jul 16 '16 at 16:16
  • 1
    @NicholasPetersen sometimes 3rd-party library can force you to do this. Example building dynammic messages in WithMessage method out of FluentValidation. There is no async API for this due to library design - WithMessage overloads are static. Other methods of passing dynamic arguments to WithMessage are strange. – lissajous May 21 '20 at 13:54

13 Answers13

341

You can access the Result property of the task, which will cause your thread to block until the result is available:

string code = GenerateCodeAsync().Result;

Note: In some cases, this might lead to a deadlock: Your call to Result blocks the main thread, thereby preventing the remainder of the async code to execute. You have the following options to make sure that this doesn't happen:

This does not mean that you should just mindlessly add .ConfigureAwait(false) after all your async calls! For a detailed analysis on why and when you should use .ConfigureAwait(false), see the following blog post:

Reyan Chougle
  • 4,917
  • 2
  • 30
  • 57
Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • 35
    If invoking `result` risks a deadlock, then when *is* it safe to get the result? Does every asynchronous call require `Task.Run` or `ConfigureAwait(false)`? – Robert Harvey Jul 15 '15 at 00:11
  • 4
    There is no "main thread" in ASP.NET (unlike a GUI app), but the deadlock is still possible because of [how](http://stackoverflow.com/q/23062154/1768303) `AspNetSynchronizationContext.Post` serializes async continuations: `Task newTask = _lastScheduledTask.ContinueWith(_ => SafeWrapCallback(action)); _lastScheduledTask = newTask;` – noseratio Aug 26 '15 at 23:36
  • 5
    @RobertHarvey: If you have no control over the implementation of the async method you're blocking on, then yes, you should wrap it with `Task.Run` to stay safe. Or use something like [`WithNoContext`](http://stackoverflow.com/q/28410046/1768303) to reduce redundant thread switching. – noseratio Aug 26 '15 at 23:37
  • 11
    NOTE: Calling `.Result` can still deadlock if the caller is on the thread pool itself. Take a scenario where the Thread Pool is of size 32 and 32 tasks are running and `Wait()/Result` waiting on a yet-to-be-scheduled 33rd task that wants to run on one of the waiting threads. – Warty Jul 16 '16 at 16:11
  • @Warty - to clarify, for the deadlock to happen, the thread pool would have to re-use *the same thread* that is waiting for the result. This will happen rarely - which is bad, because when it does happen, it won't be obvious what went wrong. – ToolmakerSteve Aug 06 '20 at 22:05
  • As mentioned by others, this can result in random deadlock conditions - totally do not recommend it. – Frank Thomas Apr 11 '21 at 19:37
  • @FrankThomas: What alternative *do* you recommend? (Serious question) I'll gladly update my answer with a solution which does not risk deadlocks. – Heinzi Apr 12 '21 at 07:17
  • @Heinzi The only solid solution is to make a program flow constantly async from start to finish. If that is not possible. The only solution I found that didn't seem to generate deadlocks is answered below: var task = Task.Run(() => GenerateCodeAsync()); task.Wait(); string code = task.Result; – Frank Thomas Apr 13 '21 at 17:30
  • @FrankThomas: Even there deadlock-freeness is not guaranteed, since `Task.Run` uses the thread pool (see ToolmakerSteve's comments on this and other answers). In addition, Task.Run executes the code in a different thread, which might cause GenerateCodeAsync to behave differently. It's really a pity that there is no built-in, deadlock-free method to execute async code synchronously. – Heinzi Apr 13 '21 at 17:57
  • @Heinzi I hear you mate. It's forced me to really decide to go async all the way or none of the way. – Frank Thomas Apr 13 '21 at 18:56
55

You should get the awaiter (GetAwaiter()) and end the wait for the completion of the asynchronous task (GetResult()).

string code = GenerateCodeAsync().GetAwaiter().GetResult();
Diego Torres
  • 1,213
  • 12
  • 5
  • 63
    We've run into deadlocks using this solution. Be warned. – Oliver Oct 09 '17 at 14:11
  • 10
    [MSDN `Task.GetAwaiter`](https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.getawaiter.aspx): This method is intended for compiler use rather than for use in application code. – foka Oct 22 '17 at 15:04
  • I still got the error Dialog popup (against my will), with the buttons 'Switch To' or 'Retry'…. however, the call actually executes and does return with a proper response. – Jonathan Hansen May 15 '19 at 20:39
  • @Oliver, I just came across this article looking for why my application in WebForms was deadlocked when I had the code above. This does indeed cause a deadlock. – Saturn K Jan 24 '22 at 22:19
33

You should be able to get this done using delegates, lambda expression

private void button2_Click(object sender, EventArgs e)
    {

        label1.Text = "waiting....";

        Task<string> sCode = Task.Run(async () =>
        {
            string msg =await GenerateCodeAsync();
            return msg;
        });

        label1.Text += sCode.Result;

    }

    private Task<string> GenerateCodeAsync()
    {
        return Task.Run<string>(() => GenerateCode());
    }

    private string GenerateCode()
    {
        Thread.Sleep(2000);
        return "I m back" ;
    }
Romano Zumbé
  • 7,893
  • 4
  • 33
  • 55
Faiyaz
  • 1,391
  • 11
  • 9
  • This snippet will not compile. The return type from Task.Run is Task. See this [MSDN blog](http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx) for full explanation. – Appetere Aug 27 '15 at 12:16
  • 5
    Thanks for pointing out, yes it returns Task type. Replacing "string sCode" to Task or var sCode should resolve it. Adding a full compile code for ease. – Faiyaz Sep 04 '15 at 07:56
  • 1
    IMHO, the essence of what makes this more likely to succeed, is using `Task.Run` to wrap the call - thus moving it to the thread pool. However, based on other answer and comments, this does not ensure it will *never* deadlock - it might simply make the deadlock "rare" - thus even harder to track down what is going wrong. – ToolmakerSteve Aug 06 '20 at 22:09
20

Microsoft Identity has extension methods which call async methods synchronously. For example there is GenerateUserIdentityAsync() method and equal CreateIdentity()

If you look at UserManagerExtensions.CreateIdentity() it look like this:

 public static ClaimsIdentity CreateIdentity<TUser, TKey>(this UserManager<TUser, TKey> manager, TUser user,
        string authenticationType)
        where TKey : IEquatable<TKey>
        where TUser : class, IUser<TKey>
    {
        if (manager == null)
        {
            throw new ArgumentNullException("manager");
        }
        return AsyncHelper.RunSync(() => manager.CreateIdentityAsync(user, authenticationType));
    }

Now lets see what AsyncHelper.RunSync does

  public static TResult RunSync<TResult>(Func<Task<TResult>> func)
    {
        var cultureUi = CultureInfo.CurrentUICulture;
        var culture = CultureInfo.CurrentCulture;
        return _myTaskFactory.StartNew(() =>
        {
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = cultureUi;
            return func();
        }).Unwrap().GetAwaiter().GetResult();
    }

So, this is your wrapper for async method. And please don't read data from Result - it will potentially block your code in ASP.

There is another way - which is suspicious for me, but you can consider it too

  Result r = null;

            YourAsyncMethod()
                .ContinueWith(t =>
                {
                    r = t.Result;
                })
                .Wait();
Vitaliy Markitanov
  • 2,205
  • 1
  • 24
  • 23
20

To prevent deadlocks I always try to use Task.Run() when I have to call an async method synchronously that @Heinzi mentions.

However the method has to be modified if the async method uses parameters. For example Task.Run(GenerateCodeAsync("test")).Result gives the error:

Argument 1: cannot convert from 'System.Threading.Tasks.Task<string>' to 'System.Action'

This could be called like this instead:

string code = Task.Run(() => GenerateCodeAsync("test")).Result;
Ogglas
  • 62,132
  • 37
  • 328
  • 418
18

I need to call this method from a synchronously method.

It's possible with GenerateCodeAsync().Result or GenerateCodeAsync().Wait(), as the other answer suggests. This would block the current thread until GenerateCodeAsync has completed.

However, your question is tagged with , and you also left the comment:

I was hoping for a simpler solution, thinking that asp.net handled this much easier than writing so many lines of code

My point is, you should not be blocking on an asynchronous method in ASP.NET. This will reduce the scalability of your web app, and may create a deadlock (when an await continuation inside GenerateCodeAsync is posted to AspNetSynchronizationContext). Using Task.Run(...).Result to offload something to a pool thread and then block will hurt the scalability even more, as it incurs +1 more thread to process a given HTTP request.

ASP.NET has built-in support for asynchronous methods, either through asynchronous controllers (in ASP.NET MVC and Web API) or directly via AsyncManager and PageAsyncTask in classic ASP.NET. You should use it. For more details, check this answer.

Community
  • 1
  • 1
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • I am overwriting `SaveChanges()` method of `DbContext`, and here i am calling the async methods, so unfortunately async controller won't help me in this situation – Catalin Mar 25 '14 at 12:36
  • @RaraituL, use `SaveChangesAsync` instead. – noseratio Mar 25 '14 at 12:43
  • i did used `SaveChangesAsync` but i needed to enforce the same methods on `SaveChanges` also – Catalin Mar 25 '14 at 13:10
  • 3
    @RaraituL, in general, you don't mix async and sync code, pick euther model. You can implement both `SaveChangesAsync` and `SaveChanges`, just make sure they don't get called both in the same ASP.NET project. – noseratio Mar 25 '14 at 23:37
  • 4
    Not all `.NET MVC` filters support asynchronous code, for example `IAuthorizationFilter`, so i cannot use `async` all the way – Catalin Mar 27 '15 at 08:32
  • 3
    @Noseratio that is an unrealistic goal. There are too many libraries with asynchronous and synchronous code as well as situations in which using only one model is not possible. MVC ActionFilters don't support asynchronous code, for example. – Justin Skiles Aug 26 '15 at 19:19
  • [My point is, you should not be blocking on an asynchronous method in ASP.NET] imaginate you must implement some IMyInterface.MySync() method and this method somehow invoked in ASP.NET. You can't change IMyInterface contract. – dimzon Oct 12 '15 at 16:14
  • 9
    @Noserato, the question is about calling asynchronous method from synchronous. Sometime you can't change API you implementing. Let's say you implementing some synchronous interface from some 3-rd party framework "A" (you can't rewrite framework to asynchronous manner) but 3rd-party library "B" you are trying to use in your implementation has only asynchronous. Also resulting product is also library and can be used anywhere including ASP.NET etc. – dimzon Oct 12 '15 at 23:24
18

Most of the answers on this thread are either complex or will result in deadlock.

Following method is simple and it will avoid deadlock because we are waiting for the task to finish and only then getting its result-

var task = Task.Run(() => GenerateCodeAsync()); 
task.Wait();
string code = task.Result;

Furthermore, here is a reference to MSDN article that talks about exactly same thing- https://blogs.msdn.microsoft.com/jpsanders/2017/08/28/asp-net-do-not-use-task-result-in-main-context/

soccer7
  • 3,547
  • 3
  • 29
  • 50
  • 1
    Despite that Microsoft reference, its `Task.Run` that makes this work (when running on ASP.NET context thread). `Wait` is irrelevant - `Result` does the equivalent when task has not completed. See [this SO Q&A](https://stackoverflow.com/q/35947937/199364). – ToolmakerSteve Aug 06 '20 at 22:22
  • @ToolmakerSteve I don't agree with you. I looked at this reference and the code between the two is not the same. Pulling the .Result directly from the task can randomly result in deadlocks. I know, I've had the issue. Very hard to troubleshoot when it happens. – Frank Thomas Apr 11 '21 at 19:51
  • I would have to say that this is the most correct solution when you cannot make the calling method async. The best answer is to make the whole flow async. – Frank Thomas Apr 11 '21 at 19:51
  • @FrankThomas - Looking at the source reference mentioned in https://stackoverflow.com/a/35948021/199364, `Task.Wait` tests `IsWaitNotificationEnabledOrNotRanToCompletion`, then calls `InternalWait`. `Future.Result` tests `IsWaitNotificationEnabledOrNotRanToCompletion`, then calls `GetResultCore`, which does `if (!IsCompleted) InternalWait`. I don't see any difference, w.r.t. deadlock potential. Of course its impossible to prove absence of deadlocks, and any change in code changes timing, so its entirely possible to have one approach fail randomly, and the other work .. until it doesn't. – ToolmakerSteve Apr 11 '21 at 23:11
  • (I mean its impossible to prove absence, unless the absence is provable by design or by static analysis; my point is that you can't determine that Wait doesn't cause though Result does, given the implementation shown.) – ToolmakerSteve Apr 11 '21 at 23:18
  • @ToolmakerSteve Thanks for the further explanation. I think it really comes down to trying to make the execution flows that need to be async to be async from beginning to end, whenever possible. Thanks again. – Frank Thomas Apr 13 '21 at 16:46
  • This approach is still no guarantee for elimination of a deadlock. Didn't work for me. – Chris Tophski Feb 17 '23 at 11:56
2

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
1

How about some extension methods that asynchronously await the completion of the asynchronous operation, then set a ManualResetEvent to indicate completion.

NOTE: You can use Task.Run(), however extension methods are a cleaner interface for expressing what you really want.

Tests showing how to use the extensions:

    [TestClass]
    public class TaskExtensionsTests
    {
        [TestMethod]
        public void AsynchronousOperationWithNoResult()
        {
            SampleAsynchronousOperationWithNoResult().AwaitResult();
        }

        [TestMethod]
        public void AsynchronousOperationWithResult()
        {
            Assert.AreEqual(3, SampleAsynchronousOperationWithResult(3).AwaitResult());
        }

        [TestMethod]
        [ExpectedException(typeof(Exception))]
        public void AsynchronousOperationWithNoResultThrows()
        {
            SampleAsynchronousOperationWithNoResultThrows().AwaitResult();
        }

        [TestMethod]
        [ExpectedException(typeof(Exception))]
        public void AsynchronousOperationWithResultThrows()
        {
            SampleAsynchronousOperationWithResultThrows(3).AwaitResult();
        }

        private static async Task SampleAsynchronousOperationWithNoResult()
        {
            await Task.Yield();
        }

        private static async Task<T> SampleAsynchronousOperationWithResult<T>(T result)
        {
            await Task.Yield();
            return result;
        }

        private static async Task SampleAsynchronousOperationWithNoResultThrows()
        {
            await Task.Yield();
            throw new Exception();
        }

        private static async Task<T> SampleAsynchronousOperationWithResultThrows<T>(T result)
        {
            await Task.Yield();
            throw new Exception();
        }

        [TestMethod]
        public void AsynchronousValueOperationWithNoResult()
        {
            SampleAsynchronousValueOperationWithNoResult().AwaitResult();
        }

        [TestMethod]
        public void AsynchronousValueOperationWithResult()
        {
            Assert.AreEqual(3, SampleAsynchronousValueOperationWithResult(3).AwaitResult());
        }

        [TestMethod]
        [ExpectedException(typeof(Exception))]
        public void AsynchronousValueOperationWithNoResultThrows()
        {
            SampleAsynchronousValueOperationWithNoResultThrows().AwaitResult();
        }

        [TestMethod]
        [ExpectedException(typeof(Exception))]
        public void AsynchronousValueOperationWithResultThrows()
        {
            SampleAsynchronousValueOperationWithResultThrows(3).AwaitResult();
        }

        private static async ValueTask SampleAsynchronousValueOperationWithNoResult()
        {
            await Task.Yield();
        }

        private static async ValueTask<T> SampleAsynchronousValueOperationWithResult<T>(T result)
        {
            await Task.Yield();
            return result;
        }

        private static async ValueTask SampleAsynchronousValueOperationWithNoResultThrows()
        {
            await Task.Yield();
            throw new Exception();
        }

        private static async ValueTask<T> SampleAsynchronousValueOperationWithResultThrows<T>(T result)
        {
            await Task.Yield();
            throw new Exception();
        }
    }

The extensions

    /// <summary>
    /// Defines extension methods for <see cref="Task"/> and <see cref="ValueTask"/>.
    /// </summary>
    public static class TaskExtensions
    {
        /// <summary>
        /// Synchronously await the results of an asynchronous operation without deadlocking; ignoring cancellation.
        /// </summary>
        /// <param name="task">
        /// The <see cref="Task"/> representing the pending operation.
        /// </param>
        public static void AwaitCompletion(this ValueTask task)
        {
            new SynchronousAwaiter(task, true).GetResult();
        }

        /// <summary>
        /// Synchronously await the results of an asynchronous operation without deadlocking; ignoring cancellation.
        /// </summary>
        /// <param name="task">
        /// The <see cref="Task"/> representing the pending operation.
        /// </param>
        public static void AwaitCompletion(this Task task)
        {
            new SynchronousAwaiter(task, true).GetResult();
        }

        /// <summary>
        /// Synchronously await the results of an asynchronous operation without deadlocking.
        /// </summary>
        /// <param name="task">
        /// The <see cref="Task"/> representing the pending operation.
        /// </param>
        /// <typeparam name="T">
        /// The result type of the operation.
        /// </typeparam>
        /// <returns>
        /// The result of the operation.
        /// </returns>
        public static T AwaitResult<T>(this Task<T> task)
        {
            return new SynchronousAwaiter<T>(task).GetResult();
        }

        /// <summary>
        /// Synchronously await the results of an asynchronous operation without deadlocking.
        /// </summary>
        /// <param name="task">
        /// The <see cref="Task"/> representing the pending operation.
        /// </param>
        public static void AwaitResult(this Task task)
        {
            new SynchronousAwaiter(task).GetResult();
        }

        /// <summary>
        /// Synchronously await the results of an asynchronous operation without deadlocking.
        /// </summary>
        /// <param name="task">
        /// The <see cref="ValueTask"/> representing the pending operation.
        /// </param>
        /// <typeparam name="T">
        /// The result type of the operation.
        /// </typeparam>
        /// <returns>
        /// The result of the operation.
        /// </returns>
        public static T AwaitResult<T>(this ValueTask<T> task)
        {
            return new SynchronousAwaiter<T>(task).GetResult();
        }

        /// <summary>
        /// Synchronously await the results of an asynchronous operation without deadlocking.
        /// </summary>
        /// <param name="task">
        /// The <see cref="ValueTask"/> representing the pending operation.
        /// </param>
        public static void AwaitResult(this ValueTask task)
        {
            new SynchronousAwaiter(task).GetResult();
        }

        /// <summary>
        /// Ignore the <see cref="OperationCanceledException"/> if the operation is cancelled.
        /// </summary>
        /// <param name="task">
        /// The <see cref="Task"/> representing the asynchronous operation whose cancellation is to be ignored.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/> representing the asynchronous operation whose cancellation is ignored.
        /// </returns>
        public static async Task IgnoreCancellationResult(this Task task)
        {
            try
            {
                await task.ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
            }
        }

        /// <summary>
        /// Ignore the <see cref="OperationCanceledException"/> if the operation is cancelled.
        /// </summary>
        /// <param name="task">
        /// The <see cref="ValueTask"/> representing the asynchronous operation whose cancellation is to be ignored.
        /// </param>
        /// <returns>
        /// The <see cref="ValueTask"/> representing the asynchronous operation whose cancellation is ignored.
        /// </returns>
        public static async ValueTask IgnoreCancellationResult(this ValueTask task)
        {
            try
            {
                await task.ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
            }
        }

        /// <summary>
        /// Ignore the results of an asynchronous operation allowing it to run and die silently in the background.
        /// </summary>
        /// <param name="task">
        /// The <see cref="Task"/> representing the asynchronous operation whose results are to be ignored.
        /// </param>
        public static async void IgnoreResult(this Task task)
        {
            try
            {
                await task.ConfigureAwait(false);
            }
            catch
            {
                // ignore exceptions
            }
        }

        /// <summary>
        /// Ignore the results of an asynchronous operation allowing it to run and die silently in the background.
        /// </summary>
        /// <param name="task">
        /// The <see cref="ValueTask"/> representing the asynchronous operation whose results are to be ignored.
        /// </param>
        public static async void IgnoreResult(this ValueTask task)
        {
            try
            {
                await task.ConfigureAwait(false);
            }
            catch
            {
                // ignore exceptions
            }
        }
    }

    /// <summary>
    /// Internal class for waiting for asynchronous operations that have a result.
    /// </summary>
    /// <typeparam name="TResult">
    /// The result type.
    /// </typeparam>
    public class SynchronousAwaiter<TResult>
    {
        /// <summary>
        /// The manual reset event signaling completion.
        /// </summary>
        private readonly ManualResetEvent manualResetEvent;

        /// <summary>
        /// The exception thrown by the asynchronous operation.
        /// </summary>
        private Exception exception;

        /// <summary>
        /// The result of the asynchronous operation.
        /// </summary>
        private TResult result;

        /// <summary>
        /// Initializes a new instance of the <see cref="SynchronousAwaiter{TResult}"/> class.
        /// </summary>
        /// <param name="task">
        /// The task representing an asynchronous operation.
        /// </param>
        public SynchronousAwaiter(Task<TResult> task)
        {
            this.manualResetEvent = new ManualResetEvent(false);
            this.WaitFor(task);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SynchronousAwaiter{TResult}"/> class.
        /// </summary>
        /// <param name="task">
        /// The task representing an asynchronous operation.
        /// </param>
        public SynchronousAwaiter(ValueTask<TResult> task)
        {
            this.manualResetEvent = new ManualResetEvent(false);
            this.WaitFor(task);
        }

        /// <summary>
        /// Gets a value indicating whether the operation is complete.
        /// </summary>
        public bool IsComplete => this.manualResetEvent.WaitOne(0);

        /// <summary>
        /// Synchronously get the result of an asynchronous operation.
        /// </summary>
        /// <returns>
        /// The result of the asynchronous operation.
        /// </returns>
        public TResult GetResult()
        {
            this.manualResetEvent.WaitOne();
            return this.exception != null ? throw this.exception : this.result;
        }

        /// <summary>
        /// Tries to synchronously get the result of an asynchronous operation.
        /// </summary>
        /// <param name="operationResult">
        /// The result of the operation.
        /// </param>
        /// <returns>
        /// The result of the asynchronous operation.
        /// </returns>
        public bool TryGetResult(out TResult operationResult)
        {
            if (this.IsComplete)
            {
                operationResult = this.exception != null ? throw this.exception : this.result;
                return true;
            }

            operationResult = default;
            return false;
        }

        /// <summary>
        /// Background "thread" which waits for the specified asynchronous operation to complete.
        /// </summary>
        /// <param name="task">
        /// The task.
        /// </param>
        private async void WaitFor(Task<TResult> task)
        {
            try
            {
                this.result = await task.ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                this.exception = exception;
            }
            finally
            {
                this.manualResetEvent.Set();
            }
        }

        /// <summary>
        /// Background "thread" which waits for the specified asynchronous operation to complete.
        /// </summary>
        /// <param name="task">
        /// The task.
        /// </param>
        private async void WaitFor(ValueTask<TResult> task)
        {
            try
            {
                this.result = await task.ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                this.exception = exception;
            }
            finally
            {
                this.manualResetEvent.Set();
            }
        }
    }

    /// <summary>
    /// Internal class for  waiting for  asynchronous operations that have no result.
    /// </summary>
    public class SynchronousAwaiter
    {
        /// <summary>
        /// The manual reset event signaling completion.
        /// </summary>
        private readonly ManualResetEvent manualResetEvent = new ManualResetEvent(false);

        /// <summary>
        /// The exception thrown by the asynchronous operation.
        /// </summary>
        private Exception exception;

        /// <summary>
        /// Initializes a new instance of the <see cref="SynchronousAwaiter{TResult}"/> class.
        /// </summary>
        /// <param name="task">
        /// The task representing an asynchronous operation.
        /// </param>
        /// <param name="ignoreCancellation">
        /// Indicates whether to ignore cancellation. Default is false.
        /// </param>
        public SynchronousAwaiter(Task task, bool ignoreCancellation = false)
        {
            this.manualResetEvent = new ManualResetEvent(false);
            this.WaitFor(task, ignoreCancellation);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SynchronousAwaiter{TResult}"/> class.
        /// </summary>
        /// <param name="task">
        /// The task representing an asynchronous operation.
        /// </param>
        /// <param name="ignoreCancellation">
        /// Indicates whether to ignore cancellation. Default is false.
        /// </param>
        public SynchronousAwaiter(ValueTask task, bool ignoreCancellation = false)
        {
            this.manualResetEvent = new ManualResetEvent(false);
            this.WaitFor(task, ignoreCancellation);
        }

        /// <summary>
        /// Gets a value indicating whether the operation is complete.
        /// </summary>
        public bool IsComplete => this.manualResetEvent.WaitOne(0);

        /// <summary>
        /// Synchronously get the result of an asynchronous operation.
        /// </summary>
        public void GetResult()
        {
            this.manualResetEvent.WaitOne();
            if (this.exception != null)
            {
                throw this.exception;
            }
        }

        /// <summary>
        /// Background "thread" which waits for the specified asynchronous operation to complete.
        /// </summary>
        /// <param name="task">
        /// The task.
        /// </param>
        /// <param name="ignoreCancellation">
        /// Indicates whether to ignore cancellation. Default is false.
        /// </param>
        private async void WaitFor(Task task, bool ignoreCancellation)
        {
            try
            {
                await task.ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                this.exception = exception;
            }
            finally
            {
                this.manualResetEvent.Set();
            }
        }

        /// <summary>
        /// Background "thread" which waits for the specified asynchronous operation to complete.
        /// </summary>
        /// <param name="task">
        ///     The task.
        /// </param>
        /// <param name="ignoreCancellation">
        /// Indicates whether to ignore cancellation. Default is false.
        /// </param>
        private async void WaitFor(ValueTask task, bool ignoreCancellation)
        {
            try
            {
                await task.ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                this.exception = exception;
            }
            finally
            {
                this.manualResetEvent.Set();
            }
        }
    }
}
Paul
  • 1,011
  • 10
  • 13
1

You can use Sync Method Generator library (nuget) to generate a synchronized version of this code.

Use it as follows:

[Zomp.SyncMethodGenerator.CreateSyncVersion]
public async Task<string> GenerateCodeAsync()
{
    string code = await GenerateCodeService.GenerateCodeAsync();
    return code;
}

Which will generate GenerateCode method which you can call synchronously.

The source that will be generated is:

public string GenerateCode()
{
    string code = GenerateCodeService.GenerateCode();
    return code;
}
Victor Irzak
  • 59
  • 2
  • 4
0

EDIT:

Task has Wait method, Task.Wait(), which waits for the "promise" to resolve and then continues, thus rendering it synchronous. example:


async Task<String> MyAsyncMethod() { ... }

String mySyncMethod() {

    return MyAsyncMethod().Wait();
}
Avi Tshuva
  • 246
  • 2
  • 12
  • 4
    Kindly elaborate on your Answer. How is it used? How specifically does it help to answer the Question? – Scratte Apr 29 '20 at 12:35
-1

I prefer a non blocking approach:

            Dim aw1=GenerateCodeAsync().GetAwaiter()
            While Not aw1.IsCompleted
                Application.DoEvents()
            End While
Zibri
  • 9,096
  • 3
  • 52
  • 44
-2

If you have an async method called " RefreshList " then, you can call that async method from a non-async method like below.

Task.Run(async () => { await RefreshList(); });
dush88c
  • 1,918
  • 1
  • 27
  • 34