Ordine di campi serializzati usando JSON.NET

C’è un modo per specificare l’ordine dei campi in un object JSON serializzato usando JSON.NET ?

Sarebbe sufficiente specificare che un singolo campo appare sempre per primo.

Ho seguito la chiamata del metodo JsonConvert.SerializeObject(key) tramite reflection (dove key era un IList) e ho scoperto che JsonSerializerInternalWriter.SerializeList viene chiamato. Prende una lista e scorre attraverso

for (int i = 0; i < values.Count; i++) { ...

dove valori è il parametro IList portato in.

Risposta breve è ... No, non esiste un modo integrato per impostare l'ordine in cui i campi sono elencati nella stringa JSON.

Il modo supportato consiste nell’utilizzare l’attributo JsonProperty nelle proprietà della class per cui si desidera impostare l’ordine. Leggi la documentazione dell’ordine JsonPropertyAttribute per maggiori informazioni .

Passa a JsonProperty un valore Order e il serializzatore si prenderà cura di tutto il resto.

  [JsonProperty(Order = 1)] 

Questo è molto simile al

  DataMember(Order = 1) 

dei giorni System.Runtime.Serialization .

È ansible controllare effettivamente l’ordine implementando IContractResolver o sovrascrivendo il metodo CreateProperties DefaultContractResolver .

Ecco un esempio della mia semplice implementazione di IContractResolver che ordina le proprietà in ordine alfabetico:

 public class OrderedContractResolver : DefaultContractResolver { protected override System.Collections.Generic.IList CreateProperties(System.Type type, MemberSerialization memberSerialization) { return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList(); } } 

Quindi imposta le impostazioni e serializza l’object e i campi JSON saranno in ordine alfabetico:

 var settings = new JsonSerializerSettings() { ContractResolver = new OrderedContractResolver() }; var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings); 

Nel mio caso la risposta di Mattias non ha funzionato. Il metodo CreateProperties non è mai stato chiamato.

Dopo un po ‘di debug degli interni di Newtonsoft.Json , ho trovato un’altra soluzione.

 public class JsonUtility { public static string NormalizeJsonString(string json) { // Parse json string into JObject. var parsedObject = JObject.Parse(json); // Sort properties of JObject. var normalizedObject = SortPropertiesAlphabetically(parsedObject); // Serialize JObject . return JsonConvert.SerializeObject(normalizedObject); } private static JObject SortPropertiesAlphabetically(JObject original) { var result = new JObject(); foreach (var property in original.Properties().ToList().OrderBy(p => p.Name)) { var value = property.Value as JObject; if (value != null) { value = SortPropertiesAlphabetically(value); result.Add(property.Name, value); } else { result.Add(property.Name, property.Value); } } return result; } } 

Nel mio caso la soluzione di niaher non funzionava perché non gestiva oggetti negli array.

Sulla base della sua soluzione questo è quello che mi è venuto in mente

 public static class JsonUtility { public static string NormalizeJsonString(string json) { JToken parsed = JToken.Parse(json); JToken normalized = NormalizeToken(parsed); return JsonConvert.SerializeObject(normalized); } private static JToken NormalizeToken(JToken token) { JObject o; JArray array; if ((o = token as JObject) != null) { List orderedProperties = new List(o.Properties()); orderedProperties.Sort(delegate(JProperty x, JProperty y) { return x.Name.CompareTo(y.Name); }); JObject normalized = new JObject(); foreach (JProperty property in orderedProperties) { normalized.Add(property.Name, NormalizeToken(property.Value)); } return normalized; } else if ((array = token as JArray) != null) { for (int i = 0; i < array.Count; i++) { array[i] = NormalizeToken(array[i]); } return array; } else { return token; } } } 

Come notato da Charlie, è ansible controllare in qualche modo l’ordinamento delle proprietà JSON ordinando le proprietà nella class stessa. Sfortunatamente, questo approccio non funziona per le proprietà ereditate da una class base. Le proprietà della class base verranno ordinate come sono disposte nel codice, ma appariranno prima delle proprietà della class base.

E per chiunque si chieda il motivo per cui si potrebbe voler alfabetizzare le proprietà JSON, è molto più facile lavorare con file JSON non elaborati, in particolare per le classi con molte proprietà, se ordinate.

Il seguente metodo ricorsivo usa reflection per ordinare l’elenco token interno su un’istanza di JObject esistente piuttosto che creare un nuovo grafo di oggetti ordinati. Questo codice si basa sui dettagli di implementazione interni di Json.NET e non deve essere utilizzato in produzione.

 void SortProperties(JToken token) { var obj = token as JObject; if (obj != null) { var props = typeof (JObject) .GetField("_properties", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(obj); var items = typeof (Collection) .GetField("items", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(props); ArrayList.Adapter((IList) items) .Sort(new ComparisonComparer( (x, y) => { var xProp = x as JProperty; var yProp = y as JProperty; return xProp != null && yProp != null ? string.Compare(xProp.Name, yProp.Name) : 0; })); } foreach (var child in token.Children()) { SortProperties(child); } } 

In realtà, poiché il mio object era già un JObject, ho usato la seguente soluzione:

 public class SortedJObject : JObject { public SortedJObject(JObject other) { var pairs = new List>(); foreach (var pair in other) { pairs.Add(pair); } pairs.OrderBy(p => p.Key).ForEach(pair => this[pair.Key] = pair.Value); } } 

e quindi usarlo in questo modo:

 string serializedObj = JsonConvert.SerializeObject(new SortedJObject(dataObject)); 

Se controlli (cioè scrivi) la class, metti le proprietà in ordine alfabetico e verranno serializzate in ordine alfabetico quando viene chiamato JsonConvert.SerializeObject() .

Non esiste un ordine di campi nel formato JSON, quindi la definizione di un ordine non ha senso.

{ id: 1, name: 'John' } è equivalente a { name: 'John', id: 1 } (entrambi rappresentano un’istanza di object strettamente equivalente)