"无法强制转换"源自"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. 可在各种电脑上复制
  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.

所以我认为这排除了我们的任何原生代码(或第三方(造成的破坏。但对这个问题还没有真正的了解。在我看来,它更像是数据库层中的一个bug


这是作为一个问题提交的:https://developercommunity2.visualstudio.com/t/Unable-to-cast-object-of-type-varies/1241378

我不认为这是一个完美的"根本原因";答复但似乎正是这种变通方法成功地避免了这些例外情况。

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

确切的变化是从:

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可能会更快地对对象进行垃圾收集。但它并没有影响其他任何事情——例如,连接仍然在同一时间关闭(就在using完成并处理连接时调用Execute之后(,我在调试器中确认了这一点。

正如问题中所指出的,由于没有堆损坏,我怀疑潜在的问题是一个错误,可能在System.Transactions中。不同类型的数据库正在使用中(SQLite和MSAccess/Jet(,所以我认为问题不可能出现在实际的连接对象中,这必须有所不同。

相关内容

  • 没有找到相关文章

最新更新