表单中的嵌套异步和等待

Nested Async and Await in Forms

我在 Mac Mini 上使用 Xamarin Forms 和 Xamarin Studio,我遇到了一个 async/await 问题,希望有人能帮助解决。我有一个按钮点击事件定义为:

void LoginButton_Clicked (object sender, EventArgs e)
{
  //Do some stuff
  this.HandleSignInCompleted(..);
}

然后调用一个方法来进行一些用户配置文件初始化,它需要联系服务器:

async void HandleSignInCompleted(..)
{
  var profile = await _profileService.GetAsync ().ConfigureAwait(false);

无论 ConfigureAwait 是否存在,这都会无限期地等待。简单的用户配置文件服务现在执行以下操作(仅 returns 我自己进行测试):

    public async Task<UserProfile> GetAsync()
    {
        //wrapper around app properties
        var accessToken = (string)_appProperties.Get ("token"); 

        //Tried with ConfigureAwait and without
        await Task.Delay (100);

        //TODO:replace with facebook load
        return new UserProfile (..);
    }

ConfigureAwait(false)Task.Delay 个扼流圈。没有它,它可以工作,但调试器崩溃了。这是怎么回事,我该如何解决这个问题,以便 AJAX 请求(当我将来在用户配置文件服务中替换它时)能够正常工作?

同步优于异步是一种反模式;您不仅受制于您自己的代码(必须在所有地方使用 ConfigureAwait(false)),而且受制于您调用的任何库。特别是,我 运行 过去在 Xamarin 上遇到过关于 Task.Delay 的类似问题。在您尝试将其切换为真正的网络呼叫之前,HttpClient 在某些移动平台上存在相同的问题(iOS 或 Android,不记得 ATM 了)。不确定 Facebook 是否会有类似的错误。

所以,总而言之,你真的不能那样做。而是一路拥抱async

async Task HandleSignInCompletedAsync(..)
{
  var profile = await _profileService.GetAsync ().ConfigureAwait(false);
}

async void LoginButton_Clicked (object sender, EventArgs e)
{
  //Do some stuff
  await this.HandleSignInCompletedAsync(..);
}

必要时禁用控件,但不要阻止。这种方法的一个很好的副作用是您的应用总是响应更快。