1

就在最近,我的应用程序一直不一致地抛出各种异常,例如:

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. 在我所做的任何搜索中都无法准确找到

该应用程序是一组通过 COM 从旧 VB6 代码调用的 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, ContextData contextData, 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, ContextData contextData, 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, ContextData contextData, 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.ContextData, 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

4

1 回答 1

0

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

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

确切的变化是从:

 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),所以我认为问题可能出在实际的连接对象中,而实际的连接对象可能会有所不同。

于 2020-10-30T15:04:06.887 回答