SilverlightではWebClient等を使用して、非同期で各種データの取得ができます。
なんとか同期でデータの取得ができないかと調べてみたのですが、結論としては無理っぽい。
下記サンプルはデータを非同期で作成して、作成完了を待って戻すメソッドgetStringを含むtestクラスです。
呼び出し元からすると、getStringは同期処理で動くはずです。
class test
{
private BackgroundWorker worker = new BackgroundWorker();
private AutoResetEvent are = new AutoResetEvent(false);
private string data = "";
public test()
{
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
}
public string getString()
{
data = "";
worker.RunWorkerAsync();
are.WaitOne();
return data;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(1000);
return;
}
private void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
data = "complete";
are.Set();
}
}
上記クラスの呼び出し元について、下記のように書いてみます。
private void button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(this.getData());
}
private string getData()
{
string returnStr = "";
test objTest = new test();
returnStr = objTest.getString();
return returnStr;
}
結論として、動きません。反応なしです。書き換えてみます。
private string getData()
{
string returnStr = "";
Thread newThread = new Thread(() =>
{
test objTest = new test();
returnStr = objTest.getString();
//Dispatcher.BeginInvoke(() => MessageBox.Show(returnStr));
});
newThread.Start();
return returnStr;
}
動きますが、メッセージが空白表示です。Dispatcher.BeginInvokeのコメントをはずすと、きちんと表示されます。
別スレッド内では正常に動いているようです。スレッド終了を待つように書き換えてみます。
private string getData()
{
string returnStr = "";
Thread newThread = new Thread(() =>
{
test objTest = new test();
returnStr = objTest.getString();
// Dispatcher.BeginInvoke(() => MessageBox.Show(returnStr));
});
newThread.Start();
newThread.Join();
return returnStr;
}
正常に別スレッドのデータを取得できました!
次に、WebRequestでデータを取得するように変更します。
test.getStringを書き換えます。
public string getString()
{
data = "";
var wait = new AutoResetEvent(false);
WebResponse ret = null;
WebRequest wr = WebRequest.Create(new Uri("http://localhost:49698"));
wr.BeginGetResponse(gr =>
{
ret = wr.EndGetResponse(gr);
wait.Set();
}, null);
wait.WaitOne();
var sr = new StreamReader(ret.GetResponseStream(), Encoding.UTF8);
data = sr.ReadToEnd();
ret.Close();
return data;
}
反応がありません。
getDataのThread.Joinをコメントアウトしてみます。
private string getData()
{
string returnStr = "";
Thread newThread = new Thread(() =>
{
test objTest = new test();
returnStr = objTest.getString();
// Dispatcher.BeginInvoke(() => MessageBox.Show(returnStr));
});
newThread.Start();
//newThread.Join();
return returnStr;
}
動きますが、メッセージが空白表示です。Dispatcher.BeginInvokeのコメントをはずすと、きちんと表示されます。
調べてみると、WebRequestの非同期データ取得の完了イベントは、UIスレッドに通知されるようです。
なので、UIスレッドでJoinなどの停止処理をいれていると、そこでロックがかかってしまうみたいです。
reactive extensionsを使えばできそうでもあるので、今後調べてみます。