Windows PhoneのHttpWebRequestには、同期メソッドが用意されていません。しかし、同期的に処理を行いたいというシーンも当然あると思います。ここでは、Windows Phoneで同期処理が行えるか実験してみたいと思います。
元ネタは確か七誌さんのブログだったと思います。明日起きたら元ネタを探します……
結論としては同期処理は無理。素直にRxを使いましょうです。
AutoResetEventを使って、通信の非同期処理を行っている間はスレッドを止めておいて、シグナルが立ったら抜けて、次の処理が行えるようにするイメージです。
private void button4_Click(object sender, RoutedEventArgs e) { var wait = new AutoResetEvent(false); var req = HttpWebRequest.CreateHttp("http://www.kantei.go.jp/"); WebResponse res = null; req.BeginGetResponse(ar => { res = req.EndGetResponse(ar); wait.Set(); }, null); // ここでwait.Set()メソッドが呼ばれるまでスレッドを止める wait.WaitOne(); // ここでresponseを使って好きなことが出来るはず・・・ }
このコードは、一見正しいように見えますが、WaitOneメソッドから戻って来なくなります。BeginGetResponseメソッドの完了通知には、イベントキューが使用されているみたいで、UIスレッドを止めてしまうとAsyncCallbackが実行されず、wait.Setメソッドが呼ばれないからです。
WaitOneメソッドを使う為には、スレッドを起こしてその上で実行する必要があります。HttpWebRequest用の拡張メソッドを使って、以下のようなコードが書けるようになりました。
private void button4_Click(object sender, RoutedEventArgs e) { // サブスレッドを起こす new Thread(() => { string text = ""; var req = HttpWebRequest.CreateHttp("http://www.kantei.go.jp/"); using (var res = req.GetResponse()) { var sr = new StreamReader(res.GetResponseStream(), Encoding.UTF8); text = sr.ReadToEnd(); } // TextBlockにテキストを表示するためUIスレッドへInvoke Dispatcher.BeginInvoke(() => { textBlock1.Text = text; }); }).Start(); }
非同期APIを無理やり同期APIっぽく偽装するHttpWebRequest用の拡張メソッドクラス郡です。
public static class HttpWebRequestExtensions { public static WebResponse GetResponse(this HttpWebRequest req) { var wait = new AutoResetEvent(false); WebResponse ret = null; req.BeginGetResponse(ar => { ret = req.EndGetResponse(ar); wait.Set(); }, null); wait.WaitOne(); return ret; } public static Stream GetRequestStream(this HttpWebRequest req) { var wait = new AutoResetEvent(false); Stream ret = null; req.BeginGetRequestStream(ar => { ret = req.EndGetRequestStream(ar); wait.Set(); }, null); wait.WaitOne(); return ret; } }
まぁ、素直にRxを使ってください・・・