JsonConvert.SerializeObject 更改 JSON 中字段的排序顺序
Posted
技术标签:
【中文标题】JsonConvert.SerializeObject 更改 JSON 中字段的排序顺序【英文标题】:JsonConvert.SerializeObject changes the sort order of fields in JSON 【发布时间】:2022-01-03 10:25:54 【问题描述】:如果您在子线程中对正在序列化的对象调用.GetProperty
方法,JsonConvert.SerializeObject
会更改 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;
执行此代码后,控制台上将显示以下内容:
Version
字段位于 JSON 的开头,而不是结尾
如果我们删除
_ = typeof(TestObject).GetProperty("Version");
那么字段的排序不会改变
或者如果你在主线程中调用代码,那么排序也不会改变
如果我用属性[JsonProperty (Order = 1)]
装饰我的对象,那么排序将与我在属性中指示的不同
我该如何解决?修复不使用 attr [JsonProperty (Order = 1)]
更新: 我们使用 JSON 字符串生成数字签名,如果字段顺序发生更改,数字签名将无效,因此字段顺序对我来说很重要
【问题讨论】:
使用属性是你修复它的方法。为什么会出现这个问题? 我不想将属性挂在所有类上,因为这些类有很多,而且它们都可能用于序列化为 JSON 我会考虑实施DefaultContractResolver
或继续使用JsonProperty
。除非您指定,否则属性不会保持其顺序。他们为什么要默认保持订单?
我的意思是为什么订单有问题?
我相信对根 JSON 对象使用 JObject.Parse
或类似内容会保持在 JSON 中找到的顺序。然后,您可以手动操作对象层次结构,而不是序列化/反序列化。
【参考方案1】:
因为默认JsonSerializer
使用System.Type.GetProperties()
获取属性。
GetProperties 方法不按特定顺序返回属性,例如字母顺序或声明顺序。您的代码不得依赖于返回属性的顺序,因为该顺序会有所不同。 (来源Type.GetProperties Method)
在我看来,你不应该关心 Json 中属性的顺序。如果 json 消费者真的需要这个合约,我认为你应该审查你的设计。
对象是零个或多个名称/值的无序集合 对,其中名称是字符串,值是字符串、数字、 布尔值、空值、对象或数组。 (来源RFC 7159)
【讨论】:
【参考方案2】:原来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);
【讨论】:
以上是关于JsonConvert.SerializeObject 更改 JSON 中字段的排序顺序的主要内容,如果未能解决你的问题,请参考以下文章