私はWebスクレイピングプログラムを持っています。メインフォームから、Webサイトとクライアントを選択して[Go]をクリックすると、WebRequestとHTMLAgilityPackを使用してSiteXとClientXに対する一連の要求を処理するBackgroundWorkerスレッドが開始され、各要求は複数のページになります。各BackgroundWorkerスレッドは実行されているバリデーションを持っており、問題が発生した場合、スレッドを中止したり、要求を中止したり、エラーを無視したり、(IDEから実行した場合は)コードにステップするダイアログボックスを表示します。このダイアログボックスに問題のHTMLページをうまくレンダリングして表示するWebBrowserコントロールが必要です。しかし、BackgroundWorkerスレッドから呼び出されているため、「現在のスレッドはシングルスレッドアパートメントにはありません」という例外が発生します。 ApartmentStateは私のWebBrowserコントロールを作成することができるだろうApartmentState.STAに設定するので、私は次のように行われBackgroundWorkerからWebBrowserでダイアログを作成する
protected bool ValidatePage(bool pagePasses, string msg) {
if (pagePasses == false) {
AbortIgnoreSuspend ais = new AbortIgnoreSuspend(responsehtml, msg);
ais.ShowDialog();
switch (ais.DialogResult) {
case DialogResult.Abort: // Aborts entire thread
Abort = true;
worker.CancelAsync();
return false;
case DialogResult.Cancel: // Aborts this case
Abort = true;
return false;
case DialogResult.Ignore: // Ignore and continue
return true;
case DialogResult.Retry: // Debug
Debug.Assert(false, "Suspending Thread");
return true; // Will return you to calling thread and allow you to continue
default:
return true;
}
}
return true;
}
スレッドを開始するところ私は例を発見した()で:ここで
がダイアログを作成する関数ですコードの調整は:
protected bool ValidatePage(bool pagePasses, string msg) {
if (pagePasses == false) {
bool setAbort = false;
bool assertError = false;
bool cancelWorker = false;
bool returnContinue = true;
Thread th = new Thread(() => {
AbortIgnoreSuspend ais = new AbortIgnoreSuspend(responsehtml, msg);
ais.ShowDialog();
switch (ais.DialogResult) {
case DialogResult.Abort: // Aborts entire thread
setAbort = true;
cancelWorker = true;
returnContinue = false;
break;
case DialogResult.Cancel: // Aborts this case
setAbort = true;
returnContinue = false;
break;
case DialogResult.Ignore: // Ignore and continue
returnContinue = true;
break;
case DialogResult.Retry: // Debug
assertError = true;
returnContinue = true; // Will return you to calling thread and allow you to continue
break;
default:
returnContinue = true;
break;
}
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
th.Join();
Abort = setAbort;
Debug.Assert(!assertError, "Suspending thread for debugging");
if (cancelWorker) { worker.CancelAsync(); }
return returnContinue;
}
return true;
}
しかし、これは私が原因のスレッドでの作業経験の私の不足のために、私はスレッド安全性でいくつかのミスを犯したことをかなり確信している、(私は単一のBackgroundWorkerでテストしている)動作しているように見えます。私が間違ったことをしたこと、私が逃したことは何ですか?
スレッドには問題ありません。 STAはまた、メッセージループをポンピングする必要があります。あなたはShowDialog()から無料で1つを取得します。あなたが持っている最大の問題は、ダイアログが別のウィンドウの後ろに消えることがあり、ユーザには見えないことです。また、ユーザーがポップアップすることを期待していなかったために、ユーザーが誤ってダイアログを閉じた。 –