InvalidCastException десериализует SqlException с Newtonsoft. Json - PullRequest
0 голосов
/ 17 марта 2020

У меня ошибка при десериализации строки JSON, содержащей экземпляр SqlException.

Информация об окружении: -. NET Ядро: версия 2.2 - Newtonsoft. Json: версия 11.0.1

Ошибка результата: System.InvalidCastException: «Невозможно привести объект типа« Newtonsoft. Json .Linq.JValue »к типу« System.Guid ». '

Стек:

 at System.Data.SqlClient.SqlException..ctor(SerializationInfo si, StreamingContext sc)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateISerializable(JsonReader reader, JsonISerializableContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)

Вот тест, который воспроизводит мою проблему:

[Fact(DisplayName = nameof(TestShitSingleSqlEx2))]
public async Task TestErrorSingleSqlEx2()
{
    string json = @"{
    ""$type"": ""System.Data.SqlClient.SqlException, System.Data.SqlClient"",
    ""ClassName"": ""System.Data.SqlClient.SqlException"",
    ""Message"": ""A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 40 - Could not open a connection to SQL Server)"",
    ""Data"": {
                ""$type"": ""System.Collections.ListDictionaryInternal, System.Private.CoreLib"",
    ""HelpLink.ProdName"": ""Microsoft SQL Server"",
    ""HelpLink.EvtSrc"": ""MSSQLServer"",
    ""HelpLink.EvtID"": ""0"",
    ""HelpLink.BaseHelpUrl"": ""http://go.microsoft.com/fwlink"",
    ""HelpLink.LinkId"": ""20476"",
    ""SqlError 1"": ""System.Data.SqlClient.SqlError: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 40 - Could not open a connection to SQL Server)""
    },
    ""InnerException"": null,
    ""HelpURL"": null,
    ""StackTraceString"": ""   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)\\n   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)\\n   at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)\\n   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)\\n   at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)\\n   at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)\\n   at System.Data.SqlClient.SqlConnection.OpenAsync(CancellationToken cancellationToken)\\n--- End of stack trace from previous location where exception was thrown ---\\n   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)\\n   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)\\n   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.BufferlessMoveNext(DbContext _, Boolean buffer, CancellationToken cancellationToken)\\n   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)\\n   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.MoveNext(CancellationToken cancellationToken)\\n   at System.Linq.AsyncEnumerable.SelectEnumerableAsyncIterator`2.MoveNextCore(CancellationToken cancellationToken) in D:\\\\a\\\\1\\\\s\\\\Ix.NET\\\\Source\\\\System.Interactive.Async\\\\Select.cs:line 106\\n   at System.Linq.AsyncEnumerable.AsyncIterator`1.MoveNext(CancellationToken cancellationToken) in D:\\\\a\\\\1\\\\s\\\\Ix.NET\\\\Source\\\\System.Interactive.Async\\\\AsyncIterator.cs:line 98\\n   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancellationToken)\\n   at System.Collections.Generic.AsyncEnumerableHelpers.ToArrayWithLength[T](IAsyncEnumerable`1 source, CancellationToken cancellationToken) in D:\\\\a\\\\1\\\\s\\\\Ix.NET\\\\Source\\\\System.Interactive.Async\\\\AsyncEnumerableHelpers.cs:line 48\\n   at System.Collections.Generic.AsyncEnumerableHelpers.ToArray[T](IAsyncEnumerable`1 source, CancellationToken cancellationToken) in D:\\\\a\\\\1\\\\s\\\\Ix.NET\\\\Source\\\\System.Interactive.Async\\\\AsyncEnumerableHelpers.cs:line 16\\n   at XXXXXX.Manufacturing.Sublot.EntityFramework.Repositories.SublotRepository.LoadDataModelAsync(IEnumerable`1 ids) in /src/Sublot/Sublot.EntityFramework/Repositories/SublotRepository.cs:line 28\\n   at XXXXXX.Manufacturing.EntityFramework.Repository.DbMultiMapRepository`3.OnGetAsync(IEnumerable`1 ids)\\n   at XXXXXX.Manufacturing.Repository.MultiRepository`1.GetAsync(String id)\\n   at XXXXXX.Manufacturing.Sublot.Cqrs.Handlers.SublotHandler.Handle(MoveSublotCommand command) in /src/Sublot/Sublot.Cqrs.Handlers/SublotHandler.cs:line 193\\n   at Rebus.Pipeline.Receive.HandlerInvoker`1.Invoke()\\n   at Rebus.Pipeline.Receive.DispatchIncomingMessageStep.Process(IncomingStepContext context, Func`1 next)\\n   at Rebus.Sagas.LoadSagaDataStep.Process(IncomingStepContext context, Func`1 next)\\n   at Rebus.Sagas.Exclusive.NewEnforceExclusiveSagaAccessIncomingStep.Process(IncomingStepContext context, Func`1 next)\\n   at Rebus.Pipeline.Receive.ActivateHandlersStep.Process(IncomingStepContext context, Func`1 next)\\n   at Rebus.Pipeline.Receive.HandleRoutingSlipsStep.Process(IncomingStepContext context, Func`1 next)\\n   at Rebus.Retry.Simple.FailedMessageWrapperStep.Process(IncomingStepContext context, Func`1 next)\\n   at Rebus.Pipeline.Receive.DeserializeIncomingMessageStep.Process(IncomingStepContext context, Func`1 next)\\n   at Rebus.Pipeline.Receive.HandleDeferredMessagesStep.Process(IncomingStepContext context, Func`1 next)\\n   at Rebus.Retry.FailFast.FailFastStep.Process(IncomingStepContext context, Func`1 next)\\n   at Rebus.Retry.Simple.SimpleRetryStrategyStep.DispatchWithTrackerIdentifier(Func`1 next, String identifierToTrackMessageBy, ITransactionContext transactionContext, String messageId, String secondLevelMessageId)"",
    ""RemoteStackTraceString"": null,
    ""RemoteStackIndex"": 0,
    ""ExceptionMethod"": null,
    ""HResult"": -2146232060,
    ""Source"": ""Core .Net SqlClient Data Provider"",
    ""WatsonBuckets"": null,
    ""Errors"": null,
    ""ClientConnectionId"": ""00000000-0000-0000-0000-000000000000""
    }";

    var settings = new JsonSerializerSettings()
    {
        TypeNameHandling = TypeNameHandling.All,
    }; ;

    var cmd = JsonConvert.DeserializeObject<System.Data.SqlClient.SqlException>(json, settings);
}

Я уже проверял, что с TypeNameHandling.None (значение по умолчанию) он работает. Но у меня была эта ошибка в производственной среде (с использованием rebus v5.4.0), и я не уверен, что изменил TypeNameHandling для всех сообщений.

Ответы [ 2 ]

0 голосов
/ 16 апреля 2020

Я разместил вопрос на GitHub SqlClient. Исправление, реализованное командой проекта, находится на этапе объединения, поэтому оно должно быть доступно в версиях, более новых, чем Microsoft.Data.SqlClient v1.1.2. DummyRick, учтите, что (глядя на трассировку стека SqlException) похоже, что вы используете пакет legacy System.Data.SqlClient вместо Microsoft.Data.SqlClient.

0 голосов
/ 18 марта 2020

Возможно, проблема в приведении свойства "" ClientConnectionId "": "" 00000000-0000-0000-0000-000000000000 ""

Фактически, если вы удалите его из json строка работает.

Проблема в том, что код, который преобразует тип, находится внутри класса System.Data.SqlClient.SqlException

Вот исходный код, который выполняет десериализацию класса:

private SqlException(SerializationInfo si, StreamingContext sc) : base(si, sc)
        {
            HResult = SqlExceptionHResult;
            foreach (SerializationEntry siEntry in si)
            {
                if ("ClientConnectionId" == siEntry.Name)
                {
                    _clientConnectionId = (Guid)siEntry.Value;
                    break;
                }
            }
        }

источник: https://github.com/dotnet/corefx/blob/master/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlException.cs

проблема заключается в том приведении: (Guid) siEntry.Value;

...