异步WCF调用在单卡在无限循环

本文关键字:单卡 无限循环 调用 WCF 异步 | 更新日期: 2023-09-27 18:08:13

我有一个问题在MonoAndroid调用WCF服务异步。我按照本教程创建了便携式类库。http://nullskull.com/a/10476775/xamarin -交叉平台-应用程序-使用wcf - - 1.部分aspx

这是我调用WCF服务的服务方法:

public async static Task<KeyExchangeModel> GetPublicKeyFromServer(KeyExchangeModel model)
{
    try
    {
        ISyncService client;
        client = new SyncServiceClient(_binding, _endpointAddress);
        var res = Task<KeyExchangeModel>.Factory.FromAsync(client.BeginGetServerPublicKey, client.EndGetServerPublicKey,
                model, null);
        await res;
        return res.Result;
    }
    catch (Exception e)
    {
        return null;
    }   
}

在这里我调用方法并等待直到它被执行。

Task<KeyExchangeModel> task = SyncServiceAgent.GetPublicKeyFromServer(keyModel);
task.Wait();
KeyExchangeModel serverModel = task.Result;

问题是,在Android上我从来没有得到的结果。它陷入了一个循环。没有异常记录在设备日志中或被抛出。

此代码在Windows单元测试和Windows Phone项目上完美工作。

我希望任何人都能帮助我。

异步WCF调用在单卡在无限循环

你的问题是这一行:task.Wait();阻塞异步代码会导致死锁。

默认情况下,await将捕获当前的"上下文",并使用该上下文来恢复async方法。在这种情况下,它可能会捕获UI上下文,它绑定到UI线程。因此,GetPublicKeyFromServer将启动WCF调用,捕获UI上下文,并返回一个未完成的任务。然后调用代码在该任务上调用Task.Wait,该阻塞 UI线程,直到异步方法完成。

之后,WCF调用返回,GetPublicKeyFromServer尝试在相同的上下文中(在UI线程上)恢复。然而,UI线程被阻塞,等待GetPublicKeyFromServer完成。这是一个典型的死锁情况。

它在单元测试中工作的原因是因为async方法捕获线程池上下文而不是UI上下文,因此它能够阻塞Wait中的一个线程池线程,而另一个线程池线程可以完成async方法。通常情况下,Windows Phone应用程序会有与Android应用程序相同的UI上下文问题,所以我怀疑测试代码有不同的地方,这就是为什么它没有在WP上死锁。

我在我的博客、MSDN的一篇文章和我的书中更详细地描述了这个问题。

此问题的最佳解决方案是使用await而不是Task.WaitTask<T>.Result。也就是说,你的调用代码应该是:

Task<KeyExchangeModel> task = SyncServiceAgent.GetPublicKeyFromServer(keyModel);
KeyExchangeModel serverModel = await task;

这将要求您的调用代码为async,这反过来要求调用者为async,等等。这种async在代码库中的"增长"是自然和正常的。