8

I see a lot of questions about calling asyc methods from sync ones, like here: How to call asynchronous method from synchronous method in C#?

I understand the solutions however, experimentally, I am seeing that I don't need to add a .Wait() or Task.Run(async () => await MyAsyncMethod()) for it to run synchronously. I have a get method that pulls information from a DB.

My code is below and when I run, it waits at var task = GetItemAsync() and I get the correct result from the DB. I find it hard to believe that the DB call could come back before the code would move on which seems to imply that it ran synchronously. Am I missing something?

public object GetItem()
{
     var task = GetItemAsync();
     var result = task.Result;

     return result
}
2
  • 1
    This is the wrong way to handle asyc operations. If you want a synchronous call, don't return and wait on a Task. If you want the DB operation asynchronous, use await to block your operation (but not the thread). Commented Dec 6, 2019 at 19:56
  • "it waits at var task = GetItemAsync()" - That makes me wonder how GetItemAsync() is written. Can you show that? Commented Dec 6, 2019 at 21:46

3 Answers 3

9

The only right way to call awaitable(method which returns Task) method is to await it. But you can await only within the method which returns Task. In legacy code it happens you cannot change the method signature because you have too many reference and you need to basically refactor entire code base. So you have these options:

.Result
.Wait()
.GetAwaiter().GetResult()

Neither of those are good. All of them are going to block the thread. But if you cannot change the method signature to await the execution, I would pick the last option - GetAwaiter().GetResult() becasue it will not wrap the exception into AggregateException

Sign up to request clarification or add additional context in comments.

2 Comments

See learn.microsoft.com/en-us/dotnet/api/…. Microsoft warns about using the last option and says it's not meant for use in code.
@IanKirkpatrick - TaskAwaiter.GetResult is no longer considered not for use. It has exactly the same "deadlock" risk as the other two alternatives. See msdn - Stephen Cleary's Async Programming - Brownfield Async Development - The Blocking Hack for a discussion of how to avoid deadlock. Requires the async method being called to use .ConfigureAwait(false), to avoid capturing UI thread (if synchronous code calls it from UI thread).
4

See The docs on Task<>.Result

System.Threading.Tasks.Task.Result is a blocking call that waits until the task finishes. So it has a built in wait call essentially.

In the remarks section of that microsoft doc:

Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.

It's unfortunate that Microsoft did not reflect this in the name of the accessor because it's an extremely critical side effect of this accessor.

Comments

4

I am facing a case where I have .netframework 4.0 calling .netstandard2.0 library using which uses await/async within with .ConfigureAwait(false) end calls.

Calling .MyMethodAsync().GetAwaiter().GetResult(); doesn't work in the .netframework context, in an AuthorizeAttribute in my concern.

Instead, to get .netframework call and return from an async .netstandard2.0 method, I wrap it within a Task.Run(async()) in the .netframework side and call the async .net2.0 method within :

  public bool MyMethod()
  {
      return Task.Run(async () =>
      {
          return await MyMethodAsync();
      }).GetAwaiter().GetResult();
  }

  public async Task<bool> MyMethodAsync(){
        // do async stuff here with .ConfigureAwait(false);
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.