少し複雑かもしれませんが、ご了承ください。
Windows フォーム アプリがあります。XSD デザイナーを介して厳密に型指定された DataSet を使用します。非同期スレッドを介してデータ アクセス クエリを実行しています。次のように実行します。
// Calling it in code on the main thread:
LoadDataList_WorkerCaller dataDelegate = new LoadDataList_WorkerCaller(LoadDataList_Worker);
IAsyncResult iar = default(IAsyncResult);
iar = dataDelegate.BeginInvoke(LoadDataList_Complete, null);
// How they are defined in the class:
private delegate TypedDataSets.DataListDataTable LoadDataList_WorkerCaller();
private TypedDataSets.DataListDataTable LoadDataList_Worker()
{
// ...blah blah
try
{
DataListTableAdapter adapter = new DataListTableAdapter();
TypedDataSets.DataListDataTable dataList = adapter.GetList(); // causes connection attempt
}
catch (SqlException sqlex)
{
// Log DB error and notify user of problem
}
return dataList;
}
private delegate void LoadDataList_CompleteCaller(IAsyncResult iar);
private void LoadDataList_Complete(IAsyncResult iar)
{
if (InvokeRequired)
{
LoadDataList_CompleteCaller invokeDelegate = new LoadDataList_CompleteCaller(LoadDataList_Complete);
Invoke(invokeDelegate, new object[] { iar });
return;
}
// Downcast the IAsyncResult to an AsyncResult -- it's safe and provides extra methods
System.Runtime.Remoting.Messaging.AsyncResult ar = (System.Runtime.Remoting.Messaging.AsyncResult)iar;
LoadDataList_WorkerCaller dataDelegate = (LoadDataList_WorkerCaller)ar.AsyncDelegate;
TypedDataSets.DataListDataTable dataList = null;
try
{
dataList = dataDelegate.EndInvoke(iar);
}
catch (Exception ex)
{
// Final fail-safe, for non-DB exceptions; we'll log 'em and such here
}
// ... use dataList object as normal
}
この SO questionの提案に基づいてマルチスレッド部分を作成しました。それは正常に動作します... TableAdapter で GetList() を呼び出すときに DB エラー (SqlExceptions の形式) がある場合を除きます。
意図的に接続文字列を破損して接続試行が失敗した場合、約 10 個の一連の SqlExceptions が .NET フレームワーク コード ランドのどこかで生成され、キャッチされます (最初の例外)。その後、アプリケーションは未処理の例外をスローし、プログラムを終了します。私がこれを知っているのは、Main メソッドにラストチャンス例外キャッチャーがあり、何かがバブルアップした場合にそれらをログに記録するからです。しかし、上記で説明したように、ワーカー関数とコールバック関数の try-catch がトリガーされることはありません。それらは完全にバイパスされているように見えますか?問題を開始する行は try-catch ブロック内にありますが。
これはSqlException であるため、キャッチする必要がありますが、代わりに、Main メソッドの try-catch が TargetInvocationException (SqlException を InnerException として) をキャッチします。エラーは予想通りです:
SQL Server への接続を確立中に、ネットワーク関連またはインスタンス固有のエラーが発生しました。サーバーが見つからないか、アクセスできませんでした。インスタンス名が正しいこと、および SQL Server がリモート接続を許可するように構成されていることを確認してください。(プロバイダー: TCP プロバイダー、エラー: 0 - ターゲット マシンがアクティブに拒否したため、接続できませんでした。)
しかし、try-catch でそれが見つからず、代わりに TargetInvocationException が発生するのはなぜですか? 何を与える?これは、例外がメインの UI スレッドとは別のスレッドで発生するためだとわかりますが、生成された例外が、try-catch を使用したコードのこの別のスレッドで生成された場合、なぜそれを無視して、代わりに完全にスレッド化し、メインスレッドをパニックさせて中止させますか?
理想的には、上記の catch (SqlException) がそれをキャッチする必要があり、DB に問題がある場合に備えて、UI を介して通知し、オフライン モードを有効にすることができます。この質問の詳細は重要ではありません。ここで完全に処理できるため、そのトラックで例外を停止できると言えば十分です...私のtry-catchが実際にそれをキャッチするだけなら!