Winforms 如何从XSD生成的类型化数据集中捕获连接超时异常?

Winforms 如何从XSD生成的类型化数据集中捕获连接超时异常?,winforms,exception-handling,multithreading,try-catch,invoke,Winforms,Exception Handling,Multithreading,Try Catch,Invoke,这可能有点复杂,但请容忍我 我有一个Windows窗体应用程序。它通过XSD设计器使用强类型数据集。我通过异步线程运行数据访问查询,执行方式如下: // Calling it in code on the main thread: LoadDataList_WorkerCaller dataDelegate = new LoadDataList_WorkerCaller(LoadDataList_Worker); IAsyncResult iar = default(IAsyncResult);

这可能有点复杂,但请容忍我

我有一个Windows窗体应用程序。它通过XSD设计器使用强类型数据集。我通过异步线程运行数据访问查询,执行方式如下:

// 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
}
我将多线程部分基于中的建议。它很好用。。。除非在TableAdapter上调用GetList()时出现DB错误(以SqlExceptions的形式)

如果我故意损坏连接字符串,导致连接尝试失败,那么在.NET framework代码区的某个地方会生成一系列大约10个SQLException并捕获(第一次机会异常)。之后,应用程序抛出一个未处理的异常并终止程序。我之所以知道这一点,是因为我在主方法上有一个最后的机会异常捕获器,如果有什么东西一直冒泡,它会记录它们。但我的try-catch-in-worker和回调函数(如上所述)从未被触发。他们好像完全被忽略了?即使开始出现问题的那一行在try-catch块中

它是一个SqlException,因此应该捕获它,但是Main方法上的try catch会捕获一个TargetInvocationException(SqlException作为InnerException)。错误如预期所示:

建立与SQL Server的连接时发生与网络相关或特定于实例的错误。找不到服务器或无法访问服务器。验证实例名称是否正确,以及SQL Server是否配置为允许远程连接。(提供程序:TCP提供程序,错误:0-无法建立连接,因为目标计算机主动拒绝了它。)

但是为什么我的try-catch错过了它,而我却得到了一个Targeting异常?有什么好处?我明白这是因为异常发生在主UI线程之外的一个单独线程上,但是如果生成的异常是在我尝试捕获的代码中的这个单独线程中生成的,为什么它会忽略它,而完全在线程上释放,然后导致主线程死机并中止


理想情况下,上面的catch(SqlException)应该捕获它,我可以通过UI通知,并在出现DB问题时启用脱机模式。对于这个问题,细节无关紧要,只需说我可以在那里完全处理它,从而停止异常的运行。。。要是我的试捕真能抓住它就好了

在我看来,问题出在您发布的代码之外。如果我们假设所讨论的数据集使用的是SqlClient,并且您试图捕获的异常的完全限定类型是System.Data.SqlClient.SqlException,那么代码应该完全按照您的预期工作。对此问题的一种可能解释是,类型化数据集使用System.Data.OleDb而不是System.Data.SqlClient

在继续之前,我建议您添加另一个捕获异常的catch块,而不是SqlException。如果在这些情况下仍然无法捕获异常,那么一定是代码的结构不是您所期望的,并且异常来自其他地方。顺便说一句,最好总是用泛型catch块包装工作线程委托代码,以避免您看到的问题


另一个良好的健全性检查是完全限定SqlException的类型(System.Data SqlClient.SqlException)。在您的代码库中,可能有人声明了另一个名为SqlException的类,该类隐藏了真正的McCoy

当然,它使用的是SqlClient和all,并且异常类型是正确的(正如我通过TargetInvocationException的InnerException确认的)。我已将其更改为捕获(例外),其行为没有任何不同。我会尝试在周围放置更多的试扣,直到有东西最终被抓住为止。谢谢你至少考虑一下!我怀疑异常没有被抛出您认为应该抛出的地方。如果您还没有这样做,我建议您转储内部异常的完整堆栈框架。