SqlException fails to deserialize via BinaryFormatter #778
Description
Describe the bug
In one project I work on, RPC is done via RabbitMQ, serializing request/reply data with BinaryFormatter. Recently, I ran across an error when deserializing SqlExceptions raised on the back-end.
There appear to be two distinct exceptions raised:
TargetInvokcationException with an inner exception of InvalidCastException when the deserialized exception includes SqlException as its inner exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.InvalidCastException: Object must implement IConvertible.
at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
at System.Runtime.Serialization.FormatterConverter.Convert(Object value, Type type)
at System.Runtime.Serialization.SerializationInfo.GetValue(String name, Type type)
at System.Exception..ctor(SerializationInfo info, StreamingContext context)
at Panther.Common.Database.DBException..ctor(SerializationInfo info, StreamingContext context) in C:\BuildAgent\work\fb44abcc89900f2b\src\server\panther.common.database\DBException.cs:line 136
--- End of inner exception stack trace ---
at Panther.Proxy.Common.SyncRequestHelper.SendRequestAsync[T](Object scope, Object payload, TimeSpan timeout, String queueName) in C:\BuildAgent\work\fb44abcc89900f2b\src\server\panther.proxy.common\SyncRequestHelper.cs:line 209
at Panther.Proxy.Common.SyncRequestHelper.SendRequestAsync[T](String queueName, Object scope, Object payload, TimeSpan timeout) in C:\BuildAgent\work\fb44abcc89900f2b\src\server\panther.proxy.common\SyncRequestHelper.cs:line 116
at Panther.Common.Extensions.TaskExtensions.SynchronizeResult[T](Task`1 task) in C:\BuildAgent\work\fb44abcc89900f2b\src\server\panther.common\Extensions\TaskExtensions.cs:line 28
at Panther.Proxy.Common.SyncRequestHelper.SendRequest[T](String queueName, Object scope, Object payload, TimeSpan timeout) in C:\BuildAgent\work\fb44abcc89900f2b\src\server\panther.proxy.common\SyncRequestHelper.cs:line 75
at Panther.Proxy.Client.BaseFailoverProxy.SendRequest[T](Keys scope, Object payload) in C:\BuildAgent\work\fb44abcc89900f2b\src\server\panther.proxy.client\BaseFailoverProxy.cs:line 28
at Panther.Proxy.Client.PrivCache.PrivCacheFailoverProxy.SavePrivilegeValues(IEnumerable`1 accountPrivs, String savedBy) in C:\BuildAgent\work\fb44abcc89900f2b\src\server\panther.proxy.client\PrivCache\PrivCacheFailoverProxy.cs:line 352
at Panther.Api.Controllers.PrivilegeController.SavePrivileges(IEnumerable`1 privileges) in C:\BuildAgent\work\fb44abcc89900f2b\src\web\panther.api.core\Controllers\PrivilegeController.cs:line 270
at lambda_method(Closure , Object )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
SerializationException when the deserialized exception is SqlException itself:
System.Runtime.Serialization.SerializationException: Unable to load type Microsoft.Data.SqlClient.SqlException required for deserialization.
at System.Runtime.Serialization.ObjectManager.DoFixups()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(BinaryParser serParser, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, Boolean check)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
at testdbexception.Program.Main(String[] args) in C:\danl\testdbexception\Program.cs:line 37
To reproduce
Attached is a minimal reproduction of the issue. TestDir has functions to create a test table, insert a value, and drop the test table. Program calls into TestDir with two inserts of the same value to trigger a SqlException for a primary key violation, then serializes and deserializes the exception with BinaryFormatter.
Expected behavior
I would expect the deserialization to complete successfully, particularly given SqlException is marked as serializable, implements ISerializable, and serializes without issue.
Further technical details
Microsoft.Data.SqlClient version: latest (2.0.1)
.NET target: Core 3.1
SQL Server version: SQL Server 2016
Operating system: Windows 10 (dev machine), Server 2016 (production machine)
Activity