这可能有点复杂,但请耐心等待。
我有一个 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
}
我将多线程部分基于此 SO question中的建议。它工作正常......除非在 TableAdapter 上调用 GetList() 时出现 DB 错误(以 SqlExceptions 的形式)。
如果我故意破坏连接字符串,从而导致连接尝试失败,则会在 .NET 框架代码区域的某处生成一系列大约 10 个 SqlException 并被捕获(第一次机会异常)。之后,应用程序抛出一个未处理的异常并终止程序。我知道这一点,因为我在 Main 方法上有一个最后机会异常捕获器,它记录它们应该一直冒泡。但是,如上所述,我在 worker 和回调函数中的 try-catch 永远不会被触发。似乎它们完全被绕过了?即使开始问题的行位于 try-catch 块内。
它是一个 SqlException,因此应该被捕获,但是 Main 方法上的 try-catch 捕获了一个 TargetInvocationException(将 SqlException 作为 InnerException)。错误如预期:
建立与 SQL Server 的连接时发生与网络相关或特定于实例的错误。服务器未找到或无法访问。验证实例名称是否正确以及 SQL Server 是否配置为允许远程连接。(提供者:TCP 提供者,错误:0 - 由于目标机器主动拒绝,无法建立连接。)
但是为什么我的 try-catch 错过了它,而我却得到了 TargetInvocationException 呢?是什么赋予了?我知道这是因为异常发生在与主 UI 线程不同的线程上,但是如果生成的异常是在我有 try-catch 的代码中的这个单独线程中生成的,为什么它会忽略它并放弃完全改为线程,然后导致主线程恐慌并中止?
理想情况下,上面的捕获(SqlException)应该捕获它,并且我可以通过 UI 通知以及启用离线模式以防出现数据库问题。这个问题的细节并不重要,我只想说我可以在那里完全处理它,从而阻止异常发生......如果我的 try-catch 真的能抓住它!