WCF客户端在异步方法上阻塞

4
我正在开发WCF客户端应用程序,遇到了await/async模式的困难。似乎这一行代码: await client.LongOperationAsync(); 总是阻塞。我理解的是,线程应该退出并继续执行Main()方法,然后在异步方法完成时返回。也许我理解有误。
以下代码的输出结果始终为: Test() started
Test() error
*
*
*
...
无论何时,Test()方法在上下文返回到main方法之前都会完成。非常感谢您的任何想法。
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
请记住,在这种情况下,您不应该依赖代码执行的顺序。由于您没有等待Test方法完成,因此无法保证它会在调用方法中的任何后续代码行之前或之后完成。 - Trevor Elliott
因此,如果它按照它的顺序完成,那么这不被认为是一个错误。 - Trevor Elliott
1个回答

4
异步方法在第一个await之前同步执行;如果您的LongOperationAsync方法在第一个await之前执行了阻塞操作,则调用该方法的方法也会被阻塞。我怀疑这就是您的情况。
这可能是因为WebRequest.BeginGetResponse在执行一些工作时是同步的。请参见Stephen Toub在this question中的答案:

Async CTP的GetRequestStreamAsync和GetResponseAsync只是.NET 4中现有HttpWebRequest.BeginGetRequestStream和BeginGetResponse的简单包装器。那些Begin*方法在提交请求之前有很多设置工作要做(例如代理、DNS、连接池等),不幸的是,今天所有这些工作都在Begin*调用中同步完成。

在这种情况下,您提供了错误的域名,因此我怀疑需要一段时间才能使DNS解析失败。

2
谢谢您的回复,Thomas。我认为这确实是情况。这似乎是WCF代理非常糟糕的行为。这基本上使得直接从UI应用程序使用WCF代理变得不可能,对吗?还有其他具有“真正”异步API的代理吗? - Adam Levi
@AdamLevi,嗯,这并不是不可能,但如果你想确保它永远不会阻塞,你必须在单独的线程中执行它... 但我同意,这很糟糕。据我所知,所有代理实现最终都会调用 WebRequest.BeginGetResponse,因此它们都会遇到相同的问题。然而,您可以使用 Dns 类中的异步方法事先检测域不存在。 - Thomas Levesque

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接