0

少し複雑かもしれませんが、ご了承ください。

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が実際にそれをキャッチするだけなら!

4

1 に答える 1

0

問題はあなたが投稿したコードの外のどこかにあるようです。問題のデータセットが SqlClient を使用しており、キャッチしようとしている例外の完全修飾型が System.Data.SqlClient.SqlException であると仮定すると、コードは期待どおりに動作するはずです。この問題の考えられる説明の 1 つは、型指定されたデータセットが System.Data.SqlClient ではなく System.Data.OleDb を使用していることです。

先に進む前に、SqlException の代わりに Exception をキャッチする別の catch ブロックを追加することをお勧めします。これらの状況でも例外をキャッチできない場合は、コードの構造が予期したものではなく、例外が別の場所から発生している可能性があります。ところで、発生している問題を回避するために、ワーカー スレッド デリゲート コードを常に汎用の catch ブロックでラップすることをお勧めします。

もう 1 つの適切な健全性チェックは、SqlException (System.Data SqlClient.SqlException) の型を完全に修飾することです。コード ベースのどこかで誰かが SqlException という名前の別のクラスを宣言し、実際の McCoy を隠している可能性があります。

于 2009-12-08T20:48:14.433 に答える