Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JsonConvert.SerializeObject changes the sort order of fields in JSON

Tags:

json

c#

json.net

JsonConvert.SerializeObject changes the sorting order of fields in JSON if you call the .GetProperty method on the object being serialized in the child thread.

class Program
{

    static void Main(string[] args)
    {
        var tasks = new List<Task>();
        for (int i = 0; i < 10; i++)
        {
            var task = Task.Factory.StartNew(() =>
            {
                var token = CreateRandomToken();

                _ = typeof(TestObject).GetProperty("Version");

                var str = JsonConvert.SerializeObject(token);

                Console.WriteLine(str);
            });

            tasks.Add(task);
        }

        Task.WaitAll(tasks.ToArray());

        Console.ReadLine();
    }


    private static TestObject CreateRandomToken()
        => new TestObject { TokenHash = "123456789", Name = "Name", Version = "123" };

}

public class TestObject
{
    public string TokenHash { get; set; }

    public string Name { get; set; }

    public string Version { get; set; }
}

As a result of executing this code, the following will be displayed on the console: enter image description here

The Version field is at the beginning of the JSON, not at the end

If we remove

_ = typeof(TestObject).GetProperty("Version"); 
  • then the sorting of the fields will not change or if you call code in the main thread, then the sorting will not change either

enter image description here

if I decorate my object with the attributes [JsonProperty (Order = 1)] then the sorting will not be the same as I indicated in the attributes

How can I fix it? fix without using the attr [JsonProperty (Order = 1)]

Updated: We use a JSON string to generate a digital signature if the order of the fields changes the digital signature will not be valid, so the order of the fields is important for me

like image 449
Max Avatar asked Oct 20 '25 13:10

Max


2 Answers

Because the default JsonSerializer get properties using System.Type.GetProperties().

The GetProperties method does not return properties in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which properties are returned, because that order varies. (Source Type.GetProperties Method)

In my opinion, you shouldn't care about the order of properties in Json. If the json consumer really need this contract, I think you should review your design.

An object is an unordered collection of zero or more name/value pairs, where a name is a string and a value is a string, number, boolean, null, object, or array. (Source RFC 7159)

like image 150
Xiaofeng Zheng Avatar answered Oct 23 '25 03:10

Xiaofeng Zheng


It turns out that JsonConvert.SerializeObject doesn't guarantee the default order of fields. To specify an explicit sorting, you can use the DefaultContractResolver

Thanks Andy for the idea!

Implementation of custom DefaultContractResolver:

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

Usage example:

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

 var str = JsonConvert.SerializeObject(token, jsonSerializerSettings);
like image 29
Max Avatar answered Oct 23 '25 04:10

Max



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!