He notado un comportamiento extraño en una de nuestras aplicaciones recientemente.
Exception=System.InvalidCastException: Unable to cast object of type 'System.Data.SqlClient.SqlTransaction' to type 'System.Byte[]'. at ServiceStack.Text.Pools.BufferPool.GetCachedBuffer(Int32 minSize) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Pools\BufferPool.cs:line 55 at ServiceStack.Redis.RedisNativeClient..ctor(RedisEndpoint config) in C:\BuildAgent\work\b2a0bfe2b1c9a118\src\ServiceStack.Redis\RedisNativeClient_Utils.cs:line 447 at ServiceStack.Redis.RedisClient..ctor(RedisEndpoint config) in C:\BuildAgent\work\b2a0bfe2b1c9a118\src\ServiceStack.Redis\RedisClient.cs:line 66 at ServiceStack.Redis.RedisConfig.<>c.<.cctor>b__35_0(RedisEndpoint c) in C:\BuildAgent\work\b2a0bfe2b1c9a118\src\ServiceStack.Redis\RedisConfig.cs:line 22 at ServiceStack.Redis.RedisResolver.CreateRedisClient(RedisEndpoint config, Boolean master) in C:\BuildAgent\work\b2a0bfe2b1c9a118\src\ServiceStack.Redis\RedisResolver.cs:line 76 at ServiceStack.Redis.RedisManagerPool.GetClient() in C:\BuildAgent\work\b2a0bfe2b1c9a118\src\ServiceStack.Redis\RedisManagerPool.cs:line 214...
O
Exception=System.InvalidCastException: Unable to cast object of type 'System.Byte[]' 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.ProviderBase.DbConnectionPool.GetFromTransactedPool(Transaction& transaction) at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection) at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection) at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection) at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions) at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry) at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry) at System.Data.SqlClient.SqlConnection.Open() at ServiceStack.OrmLite.OrmLiteConnection.Open() in C:\BuildAgent\work\27e4cc16641be8c0\src\ServiceStack.OrmLite\OrmLiteConnection.cs:line 86 ...Se lanzan excepciones similares a estas dos desde varias partes de nuestra aplicación. Lo único que tienen en común todas esas excepciones es el objeto WeakReference, pero no veo una causa obvia para esta excepción. Por ejemplo, el código ServiceStack.Text que lanza esta excepción es:
private class CachedBuffer { private readonly WeakReference _reference; public int Size { get; } public bool IsAlive => _reference.IsAlive; public byte[] Buffer => (byte[])_reference.Target; public CachedBuffer(byte[] buffer) { Size = buffer.Length; _reference = new WeakReference(buffer); } }Se lanza una excepción desde el captador de la propiedad Buffer, aparentemente _reference.Target apunta al objeto SqlTransaction y no al byte[], pero _reference solo se inicializa una vez en el constructor y no se puede cambiar después, entonces, ¿cómo se podría lanzar esta excepción?
Además, nada de este código ha cambiado recientemente, por lo que no tiene sentido que de repente comience a arrojar errores. Tampoco puedo ver ninguna forma en que pudiéramos haber causado este error por algún cambio en nuestro código, ¿o me equivoco al respecto?
¿Podría ser un error en .net clr y, de ser así, cómo podría diagnosticarlo? Nuestra aplicación usa el marco .NET 4.8 y hemos visto esos errores en las máquinas Windows Server 2012 y Windows Server 2019 dentro de nuestros entornos de prueba, pero no he podido reproducirlos localmente en mi máquina de desarrollo.
Logré localizar el problema, de hecho fue nuestro propio código el que causó este error y estaba relacionado con la reflexión. Para resumir, uno de nuestros desarrolladores introdujo un código que invocaba una clonación profunda en la propiedad ExpandoObject.Keys. Esta propiedad no es una simple colección de cadenas, sino que también contiene una referencia a todo el ExpandoObject y en el fondo del ExpandoObject también hay algunos campos de WeakReference. Todavía no entiendo exactamente qué sucede, pero supongo que clonar esas WeakReferences dentro de ExpandoObject de alguna manera causó el error que experimentamos.
Gracias por tu ayuda. Inspeccioné ese código varias veces, pero me perdí por completo la invocación de la clonación profunda, porque ese método de extensión tenía un nombre muy genérico.