源自`System.Transactions.JitSafeGetContextTransaction`的“无法投射”异常?

问题描述

最近,我的应用一直不一致地抛出各种异常,如下所示:

Unable to cast object of type 'System.Threading.Thread' to type 'System.Transactions.SafeIUnkNown'. 

Unable to cast object of type 'System.Diagnostics.Process' to type 'System.Transactions.SafeIUnkNown'.    

Unable to cast object of type 'System.Drawing.solidBrush' to type 'System.Transactions.SafeIUnkNown'.

Unable to cast object of type 'System.Threading.Thread' to type 'System.Xml.Linq.XNamespace'.    

(最后一个可能是其他的次要效果

其中一些的堆栈跟踪信息粘贴在下面,但请注意,它们都有最后的3个步骤:

   at System.Transactions.Transaction.JitSafeGetContextTransaction(ContextData contextData)
   at System.Transactions.Transaction.FastGetTransaction(TransactionScope currentScope,ContextData contextData,Transaction& contextTransaction)
   at System.Transactions.Transaction.get_Current()

观察-这些例外:

  1. 频繁发生,但并非一直如此(50%?)
  2. 发生这种情况时,并不总是产生相同的异常
  3. 与我的应用程序中导致它们的代码没有明显的联系
  4. 在各种PC上均可重现
  5. 在我所做的任何搜索中都找不到精确的

该应用程序是通过较旧的VB6代码通过COM调用的一组C#DLL。但是,这种做法已经存在多年了,我们最近对它的完成方式没有任何改变。

这不是一个多线程应用程序,因此涉及System.Threading.Thread的强制转换似乎不合适。有一个使用线程的第三方模块,但我们将其作为实验进行了研究:这样做并不能解决问题,但似乎可以减少错误频率。这使我想到了它的某种资源破坏问题。


我正在寻找建议,例如:

  • 如果您之前确实见过这种异常模式,是什么原因造成的?

  • 有关如何调试根本问题的建议


示例堆栈跟踪:

Unable to cast object of type 'System.Threading.Thread' to type 'System.Transactions.SafeIUnkNown'.    
   at System.Transactions.Transaction.JitSafeGetContextTransaction(ContextData contextData)    
   at System.Transactions.Transaction.FastGetTransaction(TransactionScope currentScope,Transaction& contextTransaction)    
   at System.Transactions.Transaction.get_Current()    
   at System.Data.sqlite.sqliteConnection.open()    
   at Company.ABC.WrappedDbConnection.open()    
   at Company.ABC.Program.DoSomething()

Unable to cast object of type 'System.Threading.Thread' to type 'System.Transactions.SafeIUnkNown'.
   at System.Transactions.Transaction.JitSafeGetContextTransaction(ContextData contextData)
   at System.Transactions.Transaction.FastGetTransaction(TransactionScope currentScope,Transaction& contextTransaction)
   at System.Transactions.Transaction.get_Current()
   at System.Data.Common.ADP.IsSysTxEqualSysEsTransaction()
   at System.Data.Common.ADP.NeedManualEnlistment()
   at System.Data.OleDb.OleDbConnection.open()
   at Company.ABC.WrappedDbConnection.open()    
   at Company.ABC.Program.DoSomething()

system.invalidCastException: Unable to cast object of type 'System.Drawing.solidBrush' to type 'System.Transactions.SafeIUnkNown'.
   at System.Transactions.Transaction.JitSafeGetContextTransaction(ContextData contextData)
   at System.Transactions.Transaction.FastGetTransaction(TransactionScope currentScope,Transaction& contextTransaction)
   at System.Transactions.Transaction.get_Current()
   at System.Data.Common.ADP.IsSysTxEqualSysEsTransaction()
   at System.Data.Common.ADP.NeedManualEnlistment()
   at System.Data.OleDb.OleDbConnection.open()

   at Company.ABC.WrappedDbConnection.open()    
   at Company.ABC.Program.DoSomething()

编辑:

我尝试使用windbg(具有托管代码的SOS扩展)对此进行研究。

它能够打破异常。这是从那一点开始的堆栈跟踪:

0:000> !DumpStack
OS Thread Id: 0x2d44 (0)
Current frame: KERNELBASE!RaiseException+0x62
ChildEBP RetAddr  Caller,Callee
0019b658 750325f2 KERNELBASE!RaiseException+0x62,calling ntdll!RtlRaiseException
0019b688 774a7310 ntdll!RtlFreeHeap+0x1e0,calling ntdll!RtlFreeHeap+0x560
0019b69c 70a9f09f clr+0xf09f,calling KERNEL32!TlsGetValue
0019b6ac 70b928f1 clr!GetMetaDataPublicInterfaceFromInternal+0x9741,calling KERNELBASE!RaiseException
0019b6ec 70aae56d clr!LogHelp_NoGuiOnAssert+0x2add,calling clr!LogHelp_NoGuiOnAssert+0x2a92
0019b6f8 70aae50f clr!LogHelp_NoGuiOnAssert+0x2a7f
0019b748 70bfc1a2 clr!CreateApplicationContext+0x1c2d2,calling clr!GetMetaDataPublicInterfaceFromInternal+0x95b6
0019b77c 70e3d369 clr!CreateHistoryReader+0x72069,calling clr!CreateApplicationContext+0x1c279
0019b7dc 70bc6a59 clr!PreBindAssemblyEx+0x10959,calling clr+0xf7b0
0019b80c 09364844 (MethodDesc 08e0d5b4 +0x4c System.Transactions.Transaction.JitSafeGetContextTransaction(System.Transactions.ContextData)),calling clr!LogHelp_TerminateOnAssert+0x7f00
0019b83c 09362f2f (MethodDesc 08e0d5e4 +0x9f System.Transactions.Transaction.FastGetTransaction(System.Transactions.TransactionScope,System.Transactions.ContextData,System.Transactions.Transaction ByRef)),calling (MethodDesc 08e0d5b4 +0 System.Transactions.Transaction.JitSafeGetContextTransaction(System.Transactions.ContextData))
0019b850 09362510 (MethodDesc 08e0d5fc +0x78 System.Transactions.Transaction.get_Current()),calling (MethodDesc 08e0d5e4 +0 System.Transactions.Transaction.FastGetTransaction(System.Transactions.TransactionScope,System.Transactions.Transaction ByRef))
0019b86c 08ddf67a (MethodDesc 08e04c6c +0x14b2 System.Data.sqlite.sqliteConnection.open()),calling (MethodDesc 08e0d5fc +0 System.Transactions.Transaction.get_Current())
0019ba70 08ddd8ea (MethodDesc 08e058b0 +0x22 Company.ABC.WrappedDbConnection.open()),calling 0dfce43a

这与上面的CLR异常堆栈同步。

我主要要确定的是是否有堆“腐败”。但显然不是:

0:000> !VerifyHeap
No heap corruption detected.

因此,我认为这排除了我们的任何本机代码(或第3方)的破坏。但是仍然没有对这个问题的实际了解。在我看来,它更像是数据库层中的一个错误


此问题已在此处提交:https://developercommunity2.visualstudio.com/t/Unable-to-cast-object-of-type-varies/1241378

解决方法

我认为这不是一个完美的“根本原因”答案;但这似乎已成功避免了异常。

有问题的代码用于创建数据库连接,执行查询,然后拆除连接。

确切的更改来自:

 public class DatabaseAccessXYZ
 {
    IDbConnection connection;

     void Execute<T>(string sql,T item)
     {
         using (connection = ConnectionManagerXYZ.GetConnection(Filespec))
         {
             connection.Open();
             connection.Execute(sql,item);
         }
         ...

对此:

 public class DatabaseAccessXYZ
 {
     void Execute<T>(string sql,T item)
     {
         using (var connection = ConnectionManagerXYZ.GetConnection(Filespec))
         {
             connection.Open();
             connection.Execute(sql,item);
         }
         ...

因此connection变量的范围已更改。无论如何,它仅在这个地方使用过,它不必是一个类级别的字段。现在,该异常不再发生。

据我了解,此更改仅意味着CLR可能会更早地对对象进行垃圾收集。但这并没有影响其他任何事情,例如,连接仍然同时关闭(在Execute完成并释放连接后调用using之后)调试器。

如问题中所述,由于没有堆损坏,我怀疑潜在的问题是错误,可能是在System.Transactions中。正在使用不同类型的数据库(SQLite和MS Access / Jet),所以我认为问题不应该出在实际的连接对象上,而该连接对象必须有所不同。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...