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; }
}
Version
字段位于JSON的开头,而不是末尾
如果我们删除
_ = typeof(TestObject).GetProperty("Version");
如果我用属性
[JsonProperty (Order = 1)]
装饰我的对象,那么排序将与我在属性中指示的不同
我该如何修复它?不使用 attr 即可修复
[JsonProperty (Order = 1)]
更新: 我们使用 JSON 字符串来生成数字签名,如果字段的顺序发生变化,数字签名将无效,因此字段的顺序对我来说很重要
因为默认
JsonSerializer
使用 System.Type.GetProperties()
获取属性。
GetProperties 方法不按特定顺序(例如字母顺序或声明顺序)返回属性。您的代码不得依赖于返回属性的顺序,因为该顺序会有所不同。 (来源Type.GetProperties 方法)
在我看来,你不应该关心 Json 中属性的顺序。如果 json 消费者确实需要这个合约,我认为你应该检查你的设计。
对象是零个或多个名称/值的无序集合 对,其中名称是字符串,值是字符串、数字, 布尔值、null、对象或数组。 (来源RFC 7159)
事实证明,
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);
只需将 JsonPropertyOrder 属性添加到想要对其排序列表的模型的属性中。但它的订单号应该是-1来设置第一个订单。
示例:
utepublic class Vehicle
{
[JsonPropertyOrder(-1)]
public int Id { get; set; }
public string? Manufacturer { get; set; }
}