5

Consider this rather simple method:

private bool ValidateKey(HttpRequestMessage message)
{

}

The above method is called as follows

if (!ValidateKey(request))
{
//do something
}

Now I want to call a method inside ValidateKey which returns Task. Let's assume it is the ReadAsStringAsync method in HttpRequestMessage:

message.Content.ReadAsStringAsync();

Now since this method can run asynchronously I should ideally call it like this:

string output = await message.Content.ReadAsStringAsync();

But this will require me to change my method signature to include async and the return type to Task and then the caller too... ad infinitum.

It is possible to call ReadAsStringAsync synchronously, i.e, I am willing to have ValidateKey wait till ReadAsStringAsync completes. This will save me the trouble of changing the code just to cater to this one method.

bobbyalex
  • 2,681
  • 3
  • 30
  • 51
  • 2
    As noted in couple of answers below, calling on the Result property will result in the thread blocking till the return value from the async method is obtained. However, I found a rather excellent answer by Stephen Cleary, describing why this might not be such a good idea. http://stackoverflow.com/a/12484535/117531 – bobbyalex Mar 18 '15 at 08:41
  • 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) – Michael Freidgeim Oct 21 '16 at 02:17

3 Answers3

8

No. If the operation is inherently asynchronous you can't run it synchronously. You can however block the thread and wait for it to complete.

I would highly advise against doing that though. You should make your operation async all the way or don't bother using an async operation at all.

You can also use AsyncContext by Stephen Cleary:

string output = AsyncContext.Run(() => message.Content.ReadAsStringAsync());

If you still plan on blocking then use GetAwaiter().GetResult() as it's closer in exception handling to what await would do:

string output = message.Content.ReadAsStringAsync().GetAwaiter().GetResult();
i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • 1
    Why? Just because of one method, my entire call stacks signature has to be modified. – bobbyalex Mar 18 '15 at 08:27
  • 3
    @BobbyAlexander I know, and it's worth it. Otherwise you're limiting scalability and responsiveness and risking deadlocks. – i3arnon Mar 18 '15 at 08:28
  • 1
    Probably, but I believe it is something that can be considered on a case by case basis. For example: in the above example, say, you always know that the message content is always a 20 char string. – bobbyalex Mar 18 '15 at 08:34
  • @BobbyAlexander At the end, it's your decision. I just gave you all the information you need to make it. If you're going to block don't use `Result`, use `GetAwaiter().GetResult()`. – i3arnon Mar 18 '15 at 08:37
  • @batmaci overall, it blocks the thread. It's synchronous and not asynchronous. Compared to `GetAwaiter().GetResult()` which also blocks the thread `Result` throws an `AggregateException` instead of the actual exception. – i3arnon Aug 21 '17 at 06:55
  • A slightly different take: I have all synchronous code built upon a synchronous 3rd party API (Amazon S3). Then the API changed to async-only. So my options are to do a significant rewrite of my entire app to be all-async, or just use `GetAwaiter().GetResult()` in this one specific place and move on to fight larger issues. Thus in my situation, it's a complete no-brainer to "hack" the async API to be sync. – dlchambers Oct 27 '20 at 11:21
1

Initial (wrong) answer part (I will leave it here for future reference)

You can use Task.RunSynchronously to make the task run synchronously, while technically it is still asynchronous, but you block the current execution, so it is sort of synchronous:

Task<string> t = message.Content.ReadAsStringAsync();

t.RunSynchronously();

string result = t.Result;

This only works if your method returns a new Task (since you can only call Run once), so this won't work when the method is declared async...

Solution

Just simply wait for the result, in a synchronous way. This will block the execution.

Task<string> t = message.Content.ReadAsStringAsync();

string result = t.Result;
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
1

ReadAsStringAsync() returns a Task<string> so, in order to wait (block) for the result you just need to get the Result property:

var task = message.Content.ReadAsStringAsync();
string output = task.Result;
RePierre
  • 9,358
  • 2
  • 20
  • 37