我创建了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")
有什么问题?我做错了什么?
谢谢你的帮助!
4条答案
按热度按时间qhhrdooz1#
您是典型死锁的受害者。
task.Wait()
或task.Result
是UI线程中导致死锁的阻塞调用。永远不要这样做,只是这样做。
顺便说一句,你为什么要抓住
WebException
然后把它扔回去呢?如果你不抓住它就更好了。两者都是一样的。我还可以看到您在
GetResponse
方法中混合了异步代码和同步代码。StreamReader.ReadToEnd
是一个阻塞调用--您应该使用StreamReader.ReadToEndAsync
。还可以对返回Task或asynchronous的方法使用“Async”后缀,以遵循TAP(“基于任务的异步模式”)约定,如Jon says。
解决了上述所有问题后,您的方法应该如下所示。
jaql4c8m2#
这就是要你命的东西
这会阻塞UI线程,直到任务完成--但是任务是一个异步方法,它会在“暂停”并等待异步结果后尝试返回UI线程。它不能这样做,因为你正在阻塞UI线程...
代码中没有任何东西看起来确实需要放在UI线程上,但假设您确实 * 确实 * 希望它在那里,您应该用途:
或者只是:
现在,
Button_Click
方法不再 * 阻塞 * 直到任务完成,而是在调度一个continuation之后返回,以便在任务完成时触发(这基本上就是async/await的工作原理)。请注意,为了清楚起见,我还将
GetResponse
重命名为GetResponseAsync
。bqf10yzr3#
@克里斯·沃尔什:如果您使用Task.Run()并在该函数中调用异步任务,则该任务将在新的UI线程上运行并防止阻塞您的UI。
zf9nrax14#
使用以下代码