JsonConvert.SerializeObject 更改 JSON 中字段的排序顺序

问题描述 投票:0回答:3
如果您对子线程中正在序列化的对象调用

JsonConvert.SerializeObject

 方法,
.GetProperty
会更改 JSON 中字段的排序顺序。

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; }
}

执行此代码后,控制台上将显示以下内容: enter image description here

Version
字段位于JSON的开头,而不是末尾

如果我们删除

_ = typeof(TestObject).GetProperty("Version"); 
  • 那么字段的排序不会改变 或者如果你在主线程中调用代码,那么排序也不会改变

enter image description here

如果我用属性

[JsonProperty (Order = 1)]
装饰我的对象,那么排序将与我在属性中指示的不同

我该如何修复它?不使用 attr 即可修复

[JsonProperty (Order = 1)]

更新: 我们使用 JSON 字符串来生成数字签名,如果字段的顺序发生变化,数字签名将无效,因此字段的顺序对我来说很重要

c# json json.net
3个回答
3
投票

因为默认

JsonSerializer
使用
System.Type.GetProperties()
获取属性。

GetProperties 方法不按特定顺序(例如字母顺序或声明顺序)返回属性。您的代码不得依赖于返回属性的顺序,因为该顺序会有所不同。 (来源Type.GetProperties 方法

在我看来,你不应该关心 Json 中属性的顺序。如果 json 消费者确实需要这个合约,我认为你应该检查你的设计。

对象是零个或多个名称/值的无序集合 对,其中名称是字符串,值是字符串、数字, 布尔值、null、对象或数组。 (来源RFC 7159


3
投票

事实证明,

JsonConvert.SerializeObject
并不能保证字段的默认顺序。要指定显式排序,您可以使用
DefaultContractResolver

谢谢Andy的想法!

实现自定义

DefaultContractResolver

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

使用示例:

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

 var str = JsonConvert.SerializeObject(token, jsonSerializerSettings);

0
投票

只需将 JsonPropertyOrder 属性添加到想要对其排序列表的模型的属性中。但它的订单号应该是-1来设置第一个订单。

示例:

utepublic class Vehicle
{
    [JsonPropertyOrder(-1)]
    public int Id { get; set; }
    public string? Manufacturer { get; set; }
}
© www.soinside.com 2019 - 2024. All rights reserved.