GetAsync : not returning HttpResponseMessage

2019-07-28 23:36发布

The apps should receive httpresponsemessage from LoginUser() but it becomes not responding.

    private void button1_Click(object sender, EventArgs e)
    {
        if (LoginUser(tUser.Text, Password.Text).Result.IsSuccessStatusCode)
        {
            Notifier.Notify("Successfully logged in.. Please wait!");

        }
        else
        {
            Notifier.Notify("Please check your Credential..");
        }            
    }

    public async Task<HttpResponseMessage> LoginUser(string userid, string password)
    {
        string URI = "http://api.danubeco.com/api/userapps/authenticate";

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("c291cmF2OmtheWFs");

            using (var response = await client.GetAsync(String.Format("{0}/{1}/{2}", URI, userid, password)))
            {
                return response;
            }
        }
    }

Please help!

1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-07-29 00:25

You are blocking the UI thread and causing a deadlock. From Stephen Cleary's blog (Just replace GetJsonAsync with your LoginUser method, and GetStringAsync with client.GetAsync):

So this is what happens, starting with the top-level method (Button1_Click for UI / MyController.Get for ASP.NET):

  1. The top-level method calls GetJsonAsync (within the UI/ASP.NET context).

  2. GetJsonAsync starts the REST request by calling HttpClient.GetStringAsync (still within the context).

  3. GetStringAsync returns an uncompleted Task, indicating the REST request is not complete.

  4. GetJsonAsync awaits the Task returned by GetStringAsync. The context is captured and will be used to continue running the GetJsonAsync method later. GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete.

  5. The top-level method synchronously blocks on the Task returned by GetJsonAsync. This blocks the context thread.

  6. … Eventually, the REST request will complete. This completes the Task that was returned by GetStringAsync.

  7. The continuation for GetJsonAsync is now ready to run, and it waits for the context to be available so it can execute in the context.

  8. Deadlock. The top-level method is blocking the context thread, waiting for GetJsonAsync to complete, and GetJsonAsync is waiting for the context to be free so it can complete.

And the simple available solutions (also from the blog):

  1. In your “library” async methods, use ConfigureAwait(false) wherever possible.
  2. Don’t block on Tasks; use async all the way down.

The 2nd solution suggests that you change button1_Click into:

private async void button1_Click(object sender, EventArgs e)
{
    if ((await LoginUser(tUser.Text, Password.Text)).IsSuccessStatusCode)
    {
        Notifier.Notify("Successfully logged in.. Please wait!");

    }
    else
    {
        Notifier.Notify("Please check your Credential..");
    }            
}
查看更多
登录 后发表回答