Orden de los campos serializados usando JSON.NET


Hay una manera de especificar el orden de los campos en un objeto JSON serializado usando JSON.NET ?

Sería suficiente especificar que siempre aparece primero un solo campo.

Author: vaxquis, 2010-07-26

11 answers

Seguí la llamada al método JsonConvert.SerializeObject(key) a través de reflexión (donde la clave era un IList) y encontré que JsonSerializerInternalWriter.SerializeList se llama. Toma una lista y loops a través de via

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

Where values es el parámetro IList introducido.

Respuesta corta is...No, no hay una forma integrada de establecer el orden en que los campos se enumeran en la cadena JSON.

 -2
Author: DougJones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-06 16:11:17

La forma soportada es usar el atributo JsonProperty en las propiedades de la clase para las que desea establecer el orden. Lea la documentación de la orden JsonPropertyAttribute para obtener más información.

Pase el valor JsonProperty y Order y el serializador se encargará del resto.

 [JsonProperty(Order = 1)]

Esto es muy similar a la

 DataMember(Order = 1) 

De los System.Runtime.Serialization días.

 184
Author: Steve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-10 21:05:51

Puede controlar el orden implementando IContractResolver o anulando el método DefaultContractResolver's CreateProperties.

Aquí hay un ejemplo de mi simple implementación de IContractResolver que ordena las propiedades alfabéticamente:

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

Y luego establezca la configuración y serialice el objeto, y los campos JSON estarán en orden alfabético:

var settings = new JsonSerializerSettings()
{
    ContractResolver = new OrderedContractResolver()
};

var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
 101
Author: Mattias Nordberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-03 10:34:58

En mi caso la respuesta de Mattias no funcionó. El método CreateProperties nunca fue llamado.

Después de un poco de depuración de Newtonsoft.Json internos, se me ocurrió otra solución.

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;
    }
}
 14
Author: niaher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-17 07:47:45

En mi caso, la solución de niaher no funcionó porque no manejaba objetos en matrices.

Basado en su solución esto es lo que se me ocurrió

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<JProperty> orderedProperties = new List<JProperty>(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;
        }
    }
}
 9
Author: Tuan-Tu Tran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-18 14:16:42

Como Charlie señaló, puede controlar de alguna manera el orden de las propiedades JSON ordenando las propiedades en la propia clase. Desafortunadamente, este enfoque no funciona para propiedades heredadas de una clase base. Las propiedades de la clase base se ordenarán tal como se presentan en código, pero aparecerán antes de las propiedades de la clase base.

Y para cualquiera que se pregunte por qué desea alfabetizar las propiedades JSON, es mucho más fácil trabajar con archivos JSON sin procesar, especialmente para clases con muchas propiedades, si están ordenadas.

 2
Author: Jack Bond,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-02 23:03:34

El siguiente método recursivo utiliza la reflexión para ordenar la lista de tokens internos en una instancia JObject existente en lugar de crear un nuevo gráfico de objetos ordenados. Este código se basa en Json.NET detalles de implementación y no debe ser utilizado en la producción.

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<JToken>)
            .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);
    }
}
 0
Author: Nathan Baulch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-06 11:40:34

En realidad, como mi Objeto ya era un JObject, utilicé la siguiente solución:

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

Y luego úsalo así:

string serializedObj = JsonConvert.SerializeObject(new SortedJObject(dataObject));
 0
Author: Danny R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-08 22:49:09

Si controla (es decir, escribe) la clase, ponga las propiedades en orden alfabético y se serializarán en orden alfabético cuando se llame a JsonConvert.SerializeObject().

 0
Author: Charlie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-27 20:15:08

Si desea configurar globalmente su API con campos ordenados, combine Mattias Nordberg respuesta:

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

Con mi respuesta aquí:

Cómo forzar ASP.NET ¿Web API para devolver siempre JSON?

 0
Author: Carlo Saccone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-26 11:17:09

No hay orden de los campos en el formato JSON, por lo que definir un orden no tiene sentido.

{ id: 1, name: 'John' } es equivalente a { name: 'John', id: 1 } (ambos representan una instancia de objeto estrictamente equivalente)

 -3
Author: Darin Dimitrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-25 21:08:24