By Johan Larsson


2013-06-22 08:10:58 8 Comments

I have the following four tests and the last one hangs when I run it, my question is why this happens:

[Test]
public void CheckOnceResultTest()
{
    Assert.IsTrue(CheckStatus().Result);
}

[Test]
public async void CheckOnceAwaitTest()
{
    Assert.IsTrue(await CheckStatus());
}

[Test]
public async void CheckStatusTwiceAwaitTest()
{
    Assert.IsTrue(await CheckStatus());
    Assert.IsTrue(await CheckStatus());
}

[Test]
public async void CheckStatusTwiceResultTest()
{
    Assert.IsTrue(CheckStatus().Result); // This hangs
    Assert.IsTrue(await CheckStatus());
}

private async Task<bool> CheckStatus()
{
    var restClient = new RestClient(@"https://api.test.nordnet.se/next/1");
    Task<IRestResponse<DummyServiceStatus>> restResponse = restClient.ExecuteTaskAsync<DummyServiceStatus>(new RestRequest(Method.GET));
    IRestResponse<DummyServiceStatus> response = await restResponse;
    return response.Data.SystemRunning;
}

I use this extension method for restsharp RestClient:

public static class RestClientExt
{
    public static Task<IRestResponse<T>> ExecuteTaskAsync<T>(this RestClient client, IRestRequest request) where T : new()
    {
        var tcs = new TaskCompletionSource<IRestResponse<T>>();
        RestRequestAsyncHandle asyncHandle = client.ExecuteAsync<T>(request, tcs.SetResult);
        return tcs.Task;
    }
}
public class DummyServiceStatus
{
    public string Message { get; set; }
    public bool ValidVersion { get; set; }
    public bool SystemRunning { get; set; }
    public bool SkipPhrase { get; set; }
    public long Timestamp { get; set; }
}

Why does the last test hang?

5 comments

@Mayank Pandit 2017-11-03 10:59:26

If you are getting no callbacks or control hangs up, after calling the Service/API Async Function.

You have to configure Context to return result on the same called context. Use TestAsync().ConfigureAwait(continueOnCapturedContext: false);

You will be facing this issue only in Web Applications but not in Static void main

@davidcarr 2019-02-05 01:34:28

ConfigureAwait avoids deadlocking in certain scenarios by not running in the original thread context.

@Dark Knight 2015-10-30 11:20:02

You are blocking the UI by using Task.Result property. In MSDN Documentation they have clearly mentioned that,

"The Result property is a blocking property. If you try to access it before its task is finished, the thread that's currently active is blocked until the task completes and the value is available. In most cases, you should access the value by using Await or await instead of accessing the property directly."

The best solution for this scenario would be to remove both await & async from methods & use only Task where you're returning result. It won't mess your execution sequence.

@Joe Phillips 2018-04-23 19:37:25

Can you define "completes"? What is an exception occurs inside that task? Etc...

@Herman Schoenfeld 2015-09-07 00:46:51

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.

@Stephen Cleary 2015-10-08 10:21:05

-1 for encouraging the use of async void unit test methods and removing same-thread guarantees provided by the SynchronizationContext from the system under test.

@Herman Schoenfeld 2015-10-16 02:01:52

@StephenCleary: there's no "enouraging" of async void. It's merely employing valid c# construct to solve the deadlock issue. The above snippet is an indispensible and simple work-around to the OP's issue. Stackoverflow is about solutions to problems, not verbose self-promotion.

@Stephen Cleary 2015-10-16 02:44:07

It's obviously not "indispensible" since my solution works without async void, Task.Run, Result, or Wait.

@Herman Schoenfeld 2015-10-16 06:05:24

@StephenCleary: Your articles don't really articulate the solution (at least not clearly) and even if you had a solution, you'd use such constructs indirectly. My solution doesn't explicitly use contexts, so what? The point is, mine works and it's a one-liner. Didn't need two blog posts and thousands of words to solve the issue. NOTE: I don't even use async void, so I don't really know what you're on about.. Do you see "async void" anywhere in my concise and proper answer?

@Sentinel 2017-05-18 10:06:15

Vorsprung durch technik. You gotta love Germanic efficiency.

@user3818229 2017-05-21 12:30:41

Could you explain why it work's please? What is the difference between this solution and using just Result property?

@ironstone13 2017-09-06 19:39:04

@HermanSchoenfeld, if you added the why to the how, I believe your answer would benefit a lot.

@Andrew Backer 2017-09-11 09:32:31

This is the right and simple way to go when you just need to sync call an async method. For example, all of refit, restease and other api generators give only async methods. Sometimes you just wanna call the damn things and not asyncify the entire class.

@SO used to be good 2017-09-22 10:30:45

I know this is kind of late, but you should be using .GetAwaiter().GetResult() instead of .Result so that any Exception is not wrapped.

@AndyUK 2018-06-15 06:44:04

That first single line of code ought to be the accepted answer. Many thanks for clearing this particular hassle up for me. You can safely disregard those other sniping comments.

@Nick 2018-08-21 21:42:37

How can this solution be used to get the actual result? If the async method returns a Task<ResultObject>, how can I get the ResultObject without calling .Result? The solution proposed only calls the async method; it doesn't provide the return value.

@user1751825 2018-10-07 10:57:33

Both options work for me. All other solutions I'd tried either caused my function to run asynchronously, or would hang the main thread. Use the first if you need the result, the second if you don't.

@MichaelDarkBlue 2019-01-04 15:20:12

I am using VB.net so this solution is perfect. But you need to change the lambda expression to Task.Run(function () asyncMethod() end function).Wait()

@Vladimir 2014-12-20 15:05:49

You can avoid deadlock adding ConfigureAwait(false) to this line:

IRestResponse<DummyServiceStatus> response = await restResponse;

=>

IRestResponse<DummyServiceStatus> response = await restResponse.ConfigureAwait(false);

I've described this pitfall in my blog post Pitfalls of async/await

@Stephen Cleary 2013-06-22 08:30:52

You're running into the standard deadlock situation that I describe on my blog and in an MSDN article: the async method is attempting to schedule its continuation onto a thread that is being blocked by the call to Result.

In this case, your SynchronizationContext is the one used by NUnit to execute async void test methods. I would try using async Task test methods instead.

@Johan Larsson 2013-06-22 09:13:45

changing to async Task worked, now I need to read the contents of your links a couple of times, ty sir.

@Stephen Cleary 2016-12-07 14:24:11

@MarioLopez: The solution is to use "async all the way" (as noted in my MSDN article). In other words - as the title of my blog post states - "don't block on async code".

@Raikol Amaro 2018-08-03 21:21:53

@StephenCleary what if I have to call an async method inside a constructor? Constructors can't be async.

@Stephen Cleary 2018-08-04 00:07:04

@RaikolAmaro: Short answer: you shouldn't do I/O in constructors. Long answer: blog.stephencleary.com/2013/01/async-oop-2-constructors.html

Related Questions

Sponsored Content

6 Answered Questions

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

  • 2013-06-24 20:28:54
  • Jay Bazuzi
  • 89650 View
  • 277 Score
  • 6 Answer
  • Tags:   c# async-await

15 Answered Questions

[SOLVED] Using async/await with a forEach loop

21 Answered Questions

[SOLVED] How and when to use ‘async’ and ‘await’

14 Answered Questions

[SOLVED] How to call asynchronous method from synchronous method in C#?

  • 2012-02-18 17:49:28
  • Tower
  • 534125 View
  • 745 Score
  • 14 Answer
  • Tags:   c# async-await

6 Answered Questions

[SOLVED] HttpClient.GetAsync(...) never returns when using await/async

10 Answered Questions

[SOLVED] Calling the base constructor in C#

2 Answered Questions

[SOLVED] await vs Task.Wait - Deadlock?

17 Answered Questions

[SOLVED] Virtual member call in a constructor

3 Answered Questions

[SOLVED] Awaiting an empty Task spins forever (await new Task(() => { }))

1 Answered Questions

[SOLVED] Async Await UI Deadlock

Sponsored Content