Task keeps waiting for activation

2020-03-02 03:20发布

I trying to use an API using Microsoft.Http. I followed the samples giving here http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client, but my task does not complete, keeps in status WaitingForActivation

Login button:

    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 class

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());
            }
        }
    }
}

enter image description here

3条回答
够拽才男人
2楼-- · 2020-03-02 03:45

You have a deadlock there.

The LoginAsync method will run synchronously until the first await (await client.PostAsJsonAsync("api/login", VM);). Then it will return to the event handler, and the UI thread will be blocked on the t.Wait(). When the await client.PostAsJsonAsync("api/login", VM); completes, the rest of the method is can run. The problem is that it has to run on the UI thread (on the same synchronization context), which is blocked, waiting for the task to complete. Deadlock.

You have to use await in the event handler too

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

You can find a detailed explanation on Stephen Cleary's blog.

查看更多
Root(大扎)
3楼-- · 2020-03-02 03:48

You need to make your event handler async as well:

private async void btnLogin_Click(object sender, EventArgs e) {
    try {
        _Token = await Api.LoginAsync( tbUsername.Text, tbPassword.Text);

    }
    catch (Exception ex) {
        ShowError(ex.Message);
    }
}
查看更多
Anthone
4楼-- · 2020-03-02 03:55

You can try bypass this using:

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);
    }
}

Im not recomend it, but in some cases can help.

查看更多
登录 后发表回答