2

.NET 6 System.Text.Json serializes properties in order unless it has more than 16 properties and at least 1 property is using the JsonPropertyOrder attribute.

Take the following code:

    using System.Text.Json;
    using System.Text.Json.Serialization;

    internal class Class1
    {
        [JsonPropertyOrder(1)]
        public string One => "1";
        public string Two => "2";
        public string Three => "3";
        public string Four => "4";
        public string Five => "5";
        public string Six => "6";
        public string Seven => "7";
        public string Eight => "8";
        public string Nine => "9";
        public string Ten => "10";
        public string Eleven => "11";
        public string Twelve => "12";
        public string Thirteen => "13";
        public string Fourteen => "14";
        public string Fifteen => "15";
        public string Sixteen => "16";
        //public string Seventeen => "17";
        public string Serialize()
        {
            return JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true});
        }
    }

Calling Serialize produces the following output:

{
  "Two": "2",
  "Three": "3",
  "Four": "4",
  "Five": "5",
  "Six": "6",
  "Seven": "7",
  "Eight": "8",
  "Nine": "9",
  "Ten": "10",
  "Eleven": "11",
  "Twelve": "12",
  "Thirteen": "13",
  "Fourteen": "14",
  "Fifteen": "15",
  "Sixteen": "16",
  "One": "1"
}

Uncomment the following line

public string Seventeen => "17";

and it produces the following output:

{
  "Nine": "9",
  "Fifteen": "15",
  "Fourteen": "14",
  "Thirteen": "13",
  "Twelve": "12",
  "Eleven": "11",
  "Ten": "10",
  "Sixteen": "16",
  "Seventeen": "17",
  "Seven": "7",
  "Six": "6",
  "Five": "5",
  "Four": "4",
  "Three": "3",
  "Two": "2",
  "Eight": "8",
  "One": "1"
}

If you comment out [JsonPropertyOrder(1)], the order comes out correctly.

How can we fix this?

  • https://stackoverflow.com/a/68285496 – madreflection Mar 16 '22 at 22:56
  • I agree that the definition at json.org says: An object is an unordered set of name/value pairs. However, as shown in dozens of posts on this site, there are different reasons why a programmer would need to control the order. In addition, Microsoft added the concept of ordering the output, hense the JsonPropertyOrder attribute. – Sean Hawkins Mar 16 '22 at 23:11
  • 1
    Why do you care about the order? The [order of members in C# is not defined](https://stackoverflow.com/questions/5473455/c-sharp-get-fieldinfos-propertyinfos-in-the-original-order), so if it's been working in _any_ scenario it's just luck. I feel like this is an X/Y question as if you're caring about order, then you're probably doing something wrong. – Kirk Woll Mar 16 '22 at 23:31
  • Your output contains 17 lines. As such, it makes sense that per your own definition the output is no longer sorted. What's your question? – CthenB Mar 16 '22 at 23:35
  • The underlying issue here is if you have classes inherited from base classes and you want the serialization to come out in a particular order, you had better stick to under 16 properties or it doesn't work. Newtonsoft does not have this issue! – Sean Hawkins Mar 17 '22 at 00:05
  • 1
    Yes. That is how Newtonsoft works and was how the .NET 6 proposal for this feature was proposed: "If there is a "tie" in the values, the reflection order is used. This is also consistent with Newtsonsoft." (https://github.com/dotnet/runtime/issues/54748). The reason I need the ordering consistent is that I am using the JSON output as a test harness to compare the output from prior runs of very complicated class hierarchies to ensure that developers do not break existing functionality. Comparing the prior serialization to this one, was an easy way to do it and worked with Newtonsoft, but not... – Sean Hawkins Mar 17 '22 at 00:42
  • with System.Text.Json. Regardless, I found another solution by removing the [JsonPropertyOrder] attribute dealing with the few items that come in the wrong order. – Sean Hawkins Mar 17 '22 at 00:44
  • It's probably worth reporting this as a bug in System.Text.Json. I can't see any intentional reason for it to not serialize properties in the reflected order after a certain point. – Collin Dauphinee Mar 17 '22 at 00:53
  • This is hugely important for us. We stream our Json between systems - order is critical. – Adam Jul 11 '22 at 04:58

2 Answers2

2

you don't need any [JsonProperty(Order = ..)]. if you want to serialize object prpoperties in a special order, just define them in this order.

 // [JsonPropertyOrder(1)]   remove it from class
 public string One => "1";

When you try to use [JsonPropertyOrder(+number)] with positive numbers, as a matter of fact, properties without this attribute are serialized at first, in a random order, after this properties with this attribute in an attribute order.

if you use [JsonPropertyOrder(-number)] with negative numbers, at first serialized properties with this numbers, after properties without attribute numbers.

So if you want to order all properties in a custom order, you have to put this attribute at each property. Only in this case all your properties will be properly ordered.

Serge
  • 40,935
  • 4
  • 18
  • 45
0

Try with JsonConvert.SerializeObject method

public class BaseClass1
            {
               
    
                [JsonProperty(Order = 2)]
                public string First => "F";
                [JsonProperty(Order = 1)]
                public string Last => "L";
            }
    
            internal class Class1 : BaseClass1
            {
                public string One => "1";
                public string Two => "2";
                public string Three => "3";
                [JsonProperty(Order = 3)]
                public string Four => "4";
                public string Five => "5";
                public string Six => "6";
                public string Seven => "7";
                public string Eight => "8";
                public string Nine => "9";
                public string Ten => "10";
                public string Eleven => "11";
                public string Twelve => "12";
                public string Thirteen => "13";
                public string Fourteen => "14";
                public string Fifteen => "15";
    
                public string Serialize()
                {
                    //return JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
                    return JsonConvert.SerializeObject(this, Formatting.Indented);
                }
            }
Aung
  • 313
  • 3
  • 9