单击按钮调用异步方法

Calling async method on button click

我创建了 Windows Phone 8.1 项目,我正在尝试 运行 async 方法 GetResponse<T>(string url) 单击按钮并等待方法完成,但方法永远不会完成。这是我的代码:

private void Button_Click(object sender, RoutedEventArgs 
{
      Task<List<MyObject>> task = GetResponse<MyObject>("my url");
      task.Wait();
      var items = task.Result; //break point here
}

public static async Task<List<T>> GetResponse<T>(string url)
{
    List<T> items = null;
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);

    var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
    try
    {
        Stream stream = response.GetResponseStream();
        StreamReader strReader = new StreamReader(stream);
        string text = strReader.ReadToEnd();
        items = JsonConvert.DeserializeObject<List<T>>(text);
    }
    catch (WebException)
    {
        throw;
    }
    return items;
}

它会挂在 task.Wait()

我将我的按钮点击方法更改为 async 并在 async 方法之前使用了 await,我得到了结果 (await GetResponse<string>("url"))。 Task<List<string>> task = GetResponse<string>("url") 有什么问题? 我做错了什么?

感谢您的帮助!

这是要了你的命:

task.Wait();

这会阻塞 UI 线程,直到任务完成 - 但任务是一个异步方法,它将尝试在它之后返回到 UI 线程 "pauses"并等待异步结果。它不能那样做,因为你阻塞了 UI 线程...

你的代码中没有任何东西看起来确实需要在 UI 线程上,但假设你真的 do 想要它,你应该使用:

private async void Button_Click(object sender, RoutedEventArgs 
{
    Task<List<MyObject>> task = GetResponse<MyObject>("my url");
    var items = await task;
    // Presumably use items here
}

或者只是:

private async void Button_Click(object sender, RoutedEventArgs 
{
    var items = await GetResponse<MyObject>("my url");
    // Presumably use items here
}

现在 阻塞 直到任务完成,Button_Click 方法将 return 在安排任务完成后继续触发。 (基本上 async/await 就是这样工作的。)

请注意,为了清楚起见,我还将 GetResponse 重命名为 GetResponseAsync

您是经典僵局的受害者。 task.Wait()task.Result 是导致死锁的 UI 线程中的阻塞调用。

Don't block in the UI thread。永远不要这样做。只是 await 它。

private async void Button_Click(object sender, RoutedEventArgs 
{
      var task = GetResponseAsync<MyObject>("my url");
      var items = await task;
}

顺便说一句,你为什么要抓住 WebException 然后把它扔回去?如果你根本不抓住它会更好。两者相同。

我还看到您在 GetResponse 方法中将异步代码与同步代码混合在一起。 StreamReader.ReadToEnd 是一个阻塞调用——你应该使用 StreamReader.ReadToEndAsync.

还对 returns 任务或异步的方法使用“异步”后缀以遵循 TAP(“基于任务的异步模式”)约定,如

当您解决了上述所有问题后,您的方法应该如下所示。

public static async Task<List<T>> GetResponseAsync<T>(string url)
{
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
    var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);

    Stream stream = response.GetResponseStream();
    StreamReader strReader = new StreamReader(stream);
    string text = await strReader.ReadToEndAsync();

    return JsonConvert.DeserializeObject<List<T>>(text);
}

使用下面的代码

 Task.WaitAll(Task.Run(async () => await GetResponse<MyObject>("my url")));