单击按钮调用异步方法
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")));
我创建了 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")));