Windows Phone 8.1プロジェクトを作成し、ボタンクリックで非同期メソッドGetResponse(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()でハングします。
ボタンクリックメソッドを非同期に変更し、非同期メソッドの前にawaitを使用して結果を取得しました(await GetResponse<string>("url")
)。 Task<List<string>> task = GetResponse<string>("url")
の何が問題になっていますか?私は何を間違えていますか?
助けてくれてありがとう!
あなたは古典的なデッドロックの犠牲者です。 task.Wait()
またはtask.Result
は、デッドロックを引き起こすUIスレッドのブロッキング呼び出しです。
Iスレッドでブロックしない 。絶対にしないでください。ちょっと待って。
private async void Button_Click(object sender, RoutedEventArgs
{
var task = GetResponseAsync<MyObject>("my url");
var items = await task;
}
ところで、なぜWebException
をキャッチして、それを投げ返すのですか?単純に捕まえない方がいいでしょう。両方とも同じです。
また、GetResponse
メソッド内で非同期コードと同期コードを混合していることがわかります。 StreamReader.ReadToEnd
はブロッキング呼び出しです。StreamReader.ReadToEndAsync
を使用する必要があります。
また、 Jon says のようにTAP( "Task based Asynchronous Pattern")規約に従うためにTaskまたは非同期を返すメソッドに "Async"サフィックスを使用します。
上記のすべての懸念に対処したら、メソッドは次のようになります。
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.Wait();
これは、タスクが完了するまでUIスレッドをブロックしますが、タスクは非同期メソッドであり、「一時停止」して非同期結果を待機した後、UIスレッドに戻ろうとします。 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
}
現在、タスクが完了するまでblockingの代わりに、Button_Click
メソッドは、タスクの完了時に実行を継続するようにスケジューリングした後に戻ります。 (これが基本的にasync/awaitの仕組みです。)
わかりやすくするために、GetResponse
の名前もGetResponseAsync
に変更します。