ZiggyCreatures / FusionCache

FusionCache is an easy to use, fast and robust hybrid cache with advanced resiliency features.
MIT License
1.91k stars 97 forks source link

Newtonsoft.Json.JsonSerializationException #39

Closed arnoldsi-vii closed 2 years ago

arnoldsi-vii commented 2 years ago

Hi, The more we use the library, the more we love it, but there is odd issue happens from time to time:

Newtonsoft.Json.JsonSerializationException: Type specified in JSON 'ZiggyCreatures.Caching.Fusion.Internals.Distributed.FusionCacheDistributedEntry`1[[System.Object, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], ZiggyCreatures.FusionCache, Version=0.1.9.0, Culture=neutral, PublicKeyToken=null' is not compatible with 'ZiggyCreatures.Caching.Fusion.Internals.Distributed.FusionCacheDistributedEntry`1[[System.Collections.Generic.IEnumerable`1[[infra.Models.Notification, infra.Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], ZiggyCreatures.FusionCache, Version=0.1.9.0, Culture=neutral, PublicKeyToken=null'. Path '$type', line 1, position 171.
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolveTypeName(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, String qualifiedTypeName)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadMetadataProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, 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.CreateValueInternal(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.JsonSerializer.Deserialize(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)
   at ZiggyCreatures.Caching.Fusion.Serialization.NewtonsoftJson.FusionCacheNewtonsoftJsonSerializer.Deserialize[T](Byte[] data)
   at ZiggyCreatures.Caching.Fusion.Serialization.NewtonsoftJson.FusionCacheNewtonsoftJsonSerializer.DeserializeAsync[T](Byte[] data)
   at ZiggyCreatures.Caching.Fusion.Internals.Distributed.DistributedCacheAccessor.TryGetEntryAsync[TValue](String operationId, String key, FusionCacheEntryOptions options, Boolean hasFallbackValue, CancellationToken token)
ZiggyCreatures.Caching.Fusion.FusionCache: Warning: FUSION (O=0005a0db3f0742339f84e64d84f56196 K=f35741d8-a1aa-425e-89d9-eec64e028789:NotificationRepository.All): unable to activate FAIL-SAFE (no entries in memory or distributed)
ZiggyCreatures.Caching.Fusion.FusionCache: Warning: FUSION (O=4a99e5456567499a859d49af206e8082 K=f35741d8-a1aa-425e-89d9-eec64e028789:SettingsDBRepository.All): an error occurred while deserializing an entry

This is the entry:

{
    "$id": "1",
    "$type": "ZiggyCreatures.Caching.Fusion.Internals.Distributed.FusionCacheDistributedEntry`1[[System.Object, System.Private.CoreLib]], ZiggyCreatures.FusionCache",
    "Value": {
        "$type": "System.Collections.Generic.List`1[[infra.Models.Notification, infra.Models]], System.Private.CoreLib",
        "$values": [
            {
                "$id": "2",
                "$type": "infra.Models.Notification, infra.Models",
                "Id": 2,
                "Title": "Test",
                "Url": "https://www.youtube.com/watch?v=UBUArSZWZeg",
                "EventAlertConfigId": null,
                "ExternalClickUrl": null,
                "CreatedBy": null
            }
        ]
    }
}

This is the configuration:

services.AddFusionCacheNewtonsoftJsonSerializer(new JsonSerializerSettings
            {
                ContractResolver = new JsonIgnoreAttributeIgnorerContractResolver(),
                ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
                PreserveReferencesHandling = PreserveReferencesHandling.Objects,
                TypeNameHandling = TypeNameHandling.All
            });

We use In Memory and Redis with .net6

arnoldsi-vii commented 2 years ago

@jodydonetti After some checking it's probably TypeNameHandling = TypeNameHandling.All creating the issue due the nature of FusionCacheDistributedEntry.

jodydonetti commented 2 years ago

Hi @arnoldsi-vii , the exception seems to indicate that you tried to serialize and deserialize a piece of data using 2 different types. In particular it says these 2 types:

Personally I tend to not include type name and similar when serializing, because then you may have problems later on when deserializing, in case you've done some refactoring.

For example let's you saved a piece of data in the distributed cache with a certain type name, then you change the type name (via refactoring) and then try to deserialize it -> error.

So what I tend to do is try to include less type information in the distributed cache, and be specific when deserializing by specifying the type I want back.

After some checking it's probably TypeNameHandling = TypeNameHandling.All creating the issue due the nature of FusionCacheDistributedEntry.

Great, I hope this is solved! Let me know if there's something else I can help you with.