【问题标题】:Do an unhandled exception bypass a try/catch block?未处理的异常会绕过 try/catch 块吗?
【发布时间】:2021-02-24 13:34:39
【问题描述】:

我有这个错误,发生在我构建的 webapi 上:

An unhandled exception occurred and the process was terminated.

Application ID: /LM/W3SVC/1/ROOT/MyWebAPI

Process ID: 43144

Exception: IBM.Data.DB2.iSeries.iDB2SQLErrorException

Message: SQ20377 Character X'  3F' cannot be mapped to a valid XML character.

StackTrace:    at IBM.Data.DB2.iSeries.iDB2Exception.throwDcException(MpDcErrorInfo mpEI, MPConnection conn)
   at IBM.Data.DB2.iSeries.iDB2Command.reportDCError(Int32 rc)
   at IBM.Data.DB2.iSeries.iDB2Command.fetch()
   at IBM.Data.DB2.iSeries.iDB2DataReader.MPDataReader.FetchData(UInt32& rowsReturned, UInt32& blockNumber)
   at IBM.Data.DB2.iSeries.iDB2DataReader.MPDataReader.FetchThread()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

对 DB2 的每个查询都会被捕获,因此应该记录和管理任何错误。但相反,“有时”(并非总是)整个应用程序池会由于这些错误而关闭。

我说有时是因为记录了事件查看器(相同)上的一些错误,但不要停止 IIS 池。

它正在运行 .NET v4.0。

可能是什么?可以绕过 try/catch 吗?很奇怪……

编辑:

大多数 try/catch 都是通用的:

try
{

}
catch (Exception ex)
{

}

有些是具体的,例如:

int rowCount = 0;
SqlBuilder.Template template = null;

try
{
    template = CreateSQLTemplate(filters, "rowcount");

    using (iDB2Connection db2 = new iDB2Connection(Properties.Settings.Default.AS400Connection))
    {
        var rowCounts = db2.Query<int>(template.RawSql, template.Parameters);
        rowCount = rowCounts.Count() > 0 ? rowCounts.First() : 0;
    }
}
catch(iDB2SQLErrorException db2Sqlex)
{
    //
}
catch (Exception ex)
{
    //
}

这样就够了,不行吗?

【问题讨论】:

  • 未处理的异常是尚未被捕获的异常,即包装在 try..catch 块中..
  • 我们可以看看你的catch 吗?有一些异常不能被可靠地捕获(特别是内存不足、堆栈溢出和线程中止),但大多数 : 将被很好地捕获。如果您意外看到异常:您可能没有捕捉到您认为自己捕捉到的内容
  • 至于它取消整个过程:是的,如果异常到达堆栈顶部,就会发生这种情况。看起来您在这里运行自己的线程,所以...是的,不要让这种情况(未处理的异常)发生
  • @markzzz 好吧,您添加的代码无法编译 - 至少缺少一个大括号;并且不清楚它们在您的其他代码中的位置,所以......不可能评论
  • @markzzz 这种特殊情况是由于async void 的工作方式以及在async 上下文中如何处理异常的组合(它们通常附加到Task 不存在的对象async void 签名,导致在原始线程中引发异常,无论该线程当时在哪里)。因此,在此示例中,如果您将签名更改为async Task(然后您应该正确地await 那个Task。但主要只是举例说明异常可以“绕过”try catch 块。

标签: c# .net iis try-catch unhandled-exception


【解决方案1】:

【讨论】:

  • 这也是我的第一个赌注。
  • 这会做什么?影响条款是什么?
  • IBM 的第二个链接解决方案:Your call stack shows that the exception is happening inside a thread that the provider kicks off, which handles pre-fetching data (a performance thing). Try turning off the prefetch in the ConnectionString (EnablePreFetch=false), and then put your exception handling around the long-running query.
【解决方案2】:

.NET Framework 提供了几个可用于捕获未处理异常的事件。当您的应用程序启动时,您只需在代码中注册一次这些事件。对于 ASP.NET,您可以在 Startup 类或 Global.asax 中执行此操作

static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
     // Log the exception, display it, etc
     Debug.WriteLine(e.Exception.Message);
}

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
     // Log the exception, display it, etc
     Debug.WriteLine((e.ExceptionObject as Exception).Message);
}

【讨论】:

  • 尝试了您的解决方案。但是我仍然在事件查看器上看到未处理的异常,并且我没有看到任何(自定义)日志:(该死的,这看起来很糟糕......
【解决方案3】:

尝试在您的数据库连接中打开连接池:

var connb = new DB2ConnectionStringBuilder(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
connb.Pooling = true;
connb.MinPoolSize = 1;
connb.MaxPoolSize = 100;
var conn = new DB2Connection(connb.ConnectionString);

如果您不能或不想这样做,请确保在完成后明确关闭与数据库的每个连接。否则,当垃圾收集器拾取您打开的连接对象时,可能会引发未处理的异常。以前使用 DB2 提供程序时已观察到此问题。

【讨论】:

  • 我关闭所有连接(如果你看到代码,有“使用”)。
  • 连接池怎么样?我应该使用哪个标签?
  • @markzzz 是的,我看到了使用,但我想强调的是,您需要确保它在任何地方都可以使用。您可以尝试在最后使用 Close() 显式关闭连接吗?我知道这几乎是深奥的,但我不确定 IBM 如何在后台实现连接。关于池化,我更新了我的帖子。
【解决方案4】:

您是否尝试订阅此活动? TaskScheduler.UnobservedTaskException Event

自 .NET 框架 4.5 以来,此行为已更改,但您可以启用它以获取有关此异常来源的更多详细信息。

该事件为静态事件,建议您在应用启动时尽快订阅该事件。

不要错过编辑配置文件

<runtime>
    <ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>

这是一个使用tpl-exception-handling的例子

请注意Release mode

希望对你有帮助

【讨论】:

  • 在哪里订阅它?例子?
  • 这不是 TPL 任务。调用堆栈清楚地显示没有未处理的 TPL 任务。这是 IBM SQL Provider 手动启动的线程,用于在我能读取的范围内预取数据。
【解决方案5】:

根据堆栈跟踪,此异常发生在 DB2 自动创建的线程中。它不会运行您的任何代码,因此您无法使用 try 块捕获此异常。

  1. 配置 Visual Studio 调试器以中断未处理的异常。
  2. 试着找出那个奇怪的角色是从哪里来的。 3F 前面的那两个空白看起来很可疑。

【讨论】:

  • 第1点:我该怎么办?你能告诉我步骤吗?对于第2点:涉及的表格/数据太多,我们无法对其进行个体化。
  • This article 解释了该怎么做,但您需要能够通过附加的调试器重现问题。如果做不到这一点,我会尝试按照here 的说明使用即时调试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-23
  • 2018-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-01
相关资源
最近更新 更多