【问题标题】:Task keeps waiting for activation任务一直在等待激活
【发布时间】:2016-04-05 16:42:29
【问题描述】:

我尝试使用使用 Microsoft.Http 的 API。我按照这里给出的示例http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client,但我的任务没有完成,保持在 WaitingForActivation 状态

登录按钮:

    private void btnLogin_Click(object sender, EventArgs e) {
        try {
            var t = Api.LoginAsync( tbUsername.Text, tbPassword.Text);
            t.Wait();
            _Token = t.Result;
        }
        catch (Exception ex) {
            ShowError(ex.Message);
        }
    }

API 类

static class Api {
    private const string URLBase = "http://localhost:28929/";

    public static async Task<string> LoginAsync(string Username, string Password ) {
        using (var client = new HttpClient()) {
            client.BaseAddress = new Uri(URLBase);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            // HTTP POST
            var VM = new Usuario() { Username = Username, Password = Password};
            HttpResponseMessage response = await client.PostAsJsonAsync("api/login", VM);
            if (response.IsSuccessStatusCode) {
                return await response.Content.ReadAsAsync<string>();
            }
            else {
                throw new ApplicationException("No se pudo ingresar. Error: " + response.StatusCode.ToString());
            }
        }
    }
}

【问题讨论】:

    标签: c# api asynchronous


    【解决方案1】:

    您还需要将事件处理程序设为async

    private async void btnLogin_Click(object sender, EventArgs e) {
        try {
            _Token = await Api.LoginAsync( tbUsername.Text, tbPassword.Text);
    
        }
        catch (Exception ex) {
            ShowError(ex.Message);
        }
    }
    

    【讨论】:

    • 调用Wait 或检查任务上的Result 属性可能(并且将会)导致死锁。
    • 哦,谢谢,浪费了太多时间。我最终使用了_Token = await Api.LoginAsync( tbUsername.Text, tbPassword.Text);
    • 奇怪了,怎么连没编译的答案都能被接受为正确答案?
    • @HamletHakobyan:是第一个,他为我指明了正确的方向。他现在编辑了它。
    【解决方案2】:

    你有一个死锁。

    LoginAsync 方法将同步运行,直到第一个 await (await client.PostAsJsonAsync("api/login", VM);)。然后它将返回到事件处理程序,UI 线程将被阻塞在t.Wait() 上。当await client.PostAsJsonAsync("api/login", VM); 完成时,该方法的其余部分就可以运行了。问题是它必须在 UI 线程上运行(在相同的同步上下文中),该线程被阻塞,等待任务完成。死锁。

    您也必须在事件处理程序中使用await

    private async void btnLogin_Click(object sender, EventArgs e) {
        try {
            _Token  = await Api.LoginAsync( tbUsername.Text, tbPassword.Text);
        }
        catch (Exception ex) {
            ShowError(ex.Message);
        }
    }
    

    你可以在Stephen Cleary's blog找到详细的解释。

    【讨论】:

      【解决方案3】:

      你可以尝试绕过这个:

      private void btnLogin_Click(object sender, EventArgs e) {
          try {
              var task= Task.Run(async () =>
                         {
                             return await Api.LoginAsync( tbUsername.Text, tbPassword.Text);
                         });
               _Token  = task.Result; 
          }
          catch (Exception ex) {
              ShowError(ex.Message);
          }
      }
      

      我不推荐它,但在某些情况下可以提供帮助。

      【讨论】:

        猜你喜欢
        • 2013-12-11
        • 1970-01-01
        • 2014-06-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多