Errore di deserializzazione di Newtonons JSON.net in cui i campi in JSON cambiano ordine

Questo è un servizio WCF che riceve richieste dai dispositivi Android. La stessa richiesta funziona con i dispositivi Lollipop, non con i dispositivi jellybean, perché jellybean organizza il JSON in modo diverso durante la creazione.

L’eccezione:

Token imprevisto durante la deserializzazione dell’object: String. Percorso ‘SearchFilters.config. $ Type’, riga 1, posizione 212.

Json non funzionante:

{ "DeviceType": 2, "SearchFilters": { "config": { "$values": [ { "Collection": { "DeviceType": 2 }, "Category": "" } ], "$type": "System.Collections.Generic.List`1[[Yoosh.SharedClasses.YooshConfig, YooshSharedClassesDll]], mscorlib" } }, "RequestingUserId": "66666666-6666-6666-6666-666666666666", "APIKey": "xxx" } 

Lavoro Json:

 { "APIKey": "xxx", "DeviceType": 2, "RequestingUserId": "66666666-6666-6666-6666-666666666666", "SearchFilters": { "config": { "$type": "System.Collections.Generic.List`1[[Yoosh.SharedClasses.YooshConfig, YooshSharedClassesDll]], mscorlib", "$values": [ { "Category": "", "Collection": { "DeviceType": 2 } } ] } } } 

Alcuni campi sono in un ordine diverso. Questa è l’unica differenza.

La class C #:

 public class QueryParameters { BaseParameters m_baseParameters; Guid m_gRequestingUserId; Dictionary m_SearchFilters; [DataMember] public string APIKey { get { return m_baseParameters.APIKey; } set { m_baseParameters.APIKey = value; } } [DataMember] public BaseParameters.YooshDeviceType DeviceType { get { return m_baseParameters.DeviceType; } set { m_baseParameters.DeviceType = value; } } [DataMember] public string DeviceId { get { return m_baseParameters.DeviceId; } set { m_baseParameters.DeviceId = value; } } [DataMember] public Guid RequestingUserId { get { return m_gRequestingUserId; } set { m_gRequestingUserId = value; } } [DataMember] public Dictionary SearchFilters { get { return m_SearchFilters; } set { m_SearchFilters = value; } } } 

Versione di Json.net: 6.0.8

Impostare JsonSerializerSettings.MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead .

Secondo la documentazione :

Questo esempio deserializza JSON con MetadataPropertyHandling impostato su ReadAhead in modo che le proprietà dei metadati non debbano essere all’inizio di un object.

  string json = @"{ 'Name': 'James', 'Password': 'Password1', '$type': 'MyNamespace.User, MyAssembly' }"; object o = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, // $type no longer needs to be first MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead }); 

Si noti che questa impostazione influirà sulle prestazioni .

Infine, quando si utilizza TypeNameHandling , prendere nota di questa avvertenza dai documenti Newtonsoft :

TypeNameHandling deve essere utilizzato con caucanvas quando l’applicazione deserializza JSON da un’origine esterna. I tipi in arrivo devono essere convalidati con un SerializationBinder personalizzato quando si deserializza con un valore diverso da Nessuno.

Per una discussione sul perché questo potrebbe essere necessario, vedi TypeNameHandling caucanvas in Newtonsoft Json .