4
votes

I'm working on WCF client app, and I facing difficulties with the await/async pattern. It seems that the line: await client.LongOperationAsync(); always blocks. As I understand, the thread supposed to exit and continue on to the Main() method and then return when the async method completes, maybe I'm wrong.

The output for the code below is (always):

Test() started
Test() error
*
*
*
...

The Test() method always completes before the context returns to main. Any thoughts would be highly appreciated.

static void Main(string[] args)
{
    Program p = new Program();
    p.Test();
    while (true)
    {
        Console.WriteLine("*");
        Thread.Sleep(500);
    }       
}
private async Task Test()
{
    Console.WriteLine("Test() started");
    try
    {
        MySoapClient client = new MySoapClient(
            new BasicHttpBinding(new BasicHttpSecurityMode()),
            new EndpointAddress("http://badaddress"));
        await client.LongOperationAsync();
        Console.WriteLine("Test() success");
    }
    catch (Exception)
    {
        Console.WriteLine("Test() error");
        return;
    }
    Console.WriteLine("Test() end successfully");
}

1
Keep in mind that you shouldn't depend on the order of code executing in a case like this. Since you're not waiting for your Test method to complete, you can't guarantee whether it will complete before or after any subsequent lines of code in the calling method. - Trevor Elliott
Therefore it's not considered an error for it to complete in the order that it did. - Trevor Elliott

1 Answers

4
votes

Async methods execute synchronously until the first await; if your LongOperationAsync method performs a blocking operation before its first await, the calling method will be blocked as well. I suspect that's what happening in your case.

This is probably because WebRequest.BeginGetResponse performs some of its work synchronously. See Stephen Toub's answer to this question:

The Async CTP's GetRequestStreamAsync and GetResponseAsync are simple wrappers around the existing HttpWebRequest.BeginGetRequestStream and BeginGetResponse in .NET 4. Those Begin* methods have a lot of setup work they do (e.g. proxy, DNS, connection pooling, etc.) before they can submit a request, and unfortunately today that work all happens synchronously as part of the Begin* call.

In this case, you provided a bad domain name, so I suspect it takes a while for the DNS resolution to fail.