dotnet 10 新的 JsonIgnoreCondition
dotnet 10 新的 JsonIgnoreCondition
Intro
之前提了一个 api 建议为 JsonIgnore 添加两个扩展,WhenReading
和 WhenWriting
,主要的一个用例是 WhenReading
我们的 Api Response 里有一个字段非常的大,不需要在 response 里包含,但是从 json 里反序列化时时需要地所以不能简单地直接忽略,在使用 Newtonsoft.Json 时使用 ShouldSerialize
约定方法在序列化的时候忽略,如果有一个 WhenWriting
的 ignore 选项可以比较方便地从 Newtonsoft.Json 做迁移,去年的时候 api review approved 了,之前看到有一个关联的 PR 不过后来一直没有更新,于是尝试自己提了一个 PR 以提供支持
New Api
代码语言:javascript代码运行次数:0运行复制namespace System.Text.Json.Serialization;
public enum JsonIgnoreCondition
{
Never,
Always,
WhenWritingDefault,
WhenWritingNull,
+ WhenWriting,
+ WhenReading,
}
为 JsonIgnoreCondition
新增了 WhenWriting
/WhenReading
选项,在序列化和反序列化时进行忽略
Sample
下面我们来看一个简单的使用示例:
代码语言:javascript代码运行次数:0运行复制sealed classPerson
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWriting)]
publicint Id { get; set; }
public required string Name { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenReading)]
publicstring? Description { get; set; }
public override string ToString()
{
return$"{Id}-{Name}";
}
}
代码语言:javascript代码运行次数:0运行复制var p1 = new Person
{
Id = 1,
Name = "Jane",
Description = "Jane J"
};
Console.WriteLine("Person1");
Console.WriteLine(p1.ToJson()); // ToJson() 是一个基于 Newtonsoft.Json 的扩展方法,来方便做一些测试
var jsonP1 = JsonSerializer.Serialize(p1);
Console.WriteLine(jsonP1);
var p1Deserialized = JsonSerializer.Deserialize<Person>(jsonP1);
Console.WriteLine(p1Deserialized.ToJson());
输出结果如下:
person sample output
可以看到 Id
因为添加了 WhenWriting
的 JsonIgnoreCondition
的,在序列化的时候被忽略了,只有 Name 和 Description 输出了,在之后的反序列化中,因为 Description
添加了 [JsonIgnore(Condition = JsonIgnoreCondition.WhenReading)]
所以 Description 是没有更新值的,值是 null
又因为默认忽略了 null 的输出,所以最后的输出结果中我们是没有看到 Description
的
相信这个例子可以比较好的理解其用法,在测试的过程中还发现了一个有趣的事情,下面也分享一下
接下来示例用到的 model 定义如下:
代码语言:javascript代码运行次数:0运行复制
sealed record User(int UserId, string UserName);
sealed record User2([property:JsonIgnore(Condition = JsonIgnoreCondition.WhenWriting)]int UserId, string UserName);
sealed record User3(
[property:JsonIgnore(Condition = JsonIgnoreCondition.WhenWriting)]int UserId,
string UserName,
[property:JsonIgnore(Condition = JsonIgnoreCondition.WhenReading)]string? Description
);
sealed record User4
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWriting)]
publicint UserId { get; init; }
public required string UserName { get; init; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenReading)]
publicstring? Description { get; set; }
}
注意的话会发现这几个都是 record
测试示例如下:
var user1 = new User(1, "Mike");
var user2 = new User2(1, "Mike");
var user3 = new User3(1, "Mike", "Michael");
var user4 = new User4 { UserId = 1, UserName = "Alice", Description = "Alice " };
Console.WriteLine("User1");
Console.WriteLine(user1.ToJson());
var json1 = JsonSerializer.Serialize(user1);
Console.WriteLine(json1);
var user1Deserialized = JsonSerializer.Deserialize<User>(json1);
Console.WriteLine(user1Deserialized);
Console.WriteLine("User2");
Console.WriteLine(user2.ToJson());
var json2 = JsonSerializer.Serialize(user2);
Console.WriteLine(json2);
var user2Deserialized = JsonSerializer.Deserialize<User2>(json2);
Console.WriteLine(user2Deserialized);
Console.WriteLine("User3");
Console.WriteLine(user3.ToJson());
var json3 = JsonSerializer.Serialize(user3);
Console.WriteLine(json3);
var user3Deserialized = JsonSerializer.Deserialize<User3>(json3);
Console.WriteLine(user3Deserialized);
Console.WriteLine("User4");
Console.WriteLine(user4.ToJson());
var json4 = JsonSerializer.Serialize(user4);
Console.WriteLine(json4);
var user4Deserialized = JsonSerializer.Deserialize<User4>(json4);
Console.WriteLine(user4Deserialized);
输出结果如下:
users sample output
- User1 是没有使用 JsonIgnore attribute 的,序列化和反序列化属性都有输出和设置
- User2 设置了 Id 使用
[property:JsonIgnore(Condition = JsonIgnoreCondition.WhenWriting)]
UserId
在序列化的时候被忽略了 - User3 设置了 Id 使用
[property:JsonIgnore(Condition = JsonIgnoreCondition.WhenWriting)]
UserId
在序列化的时候被忽略了,Description
设置了[property:JsonIgnore(Condition = JsonIgnoreCondition.WhenReading)]
但是从输出结果可以看出来,Description
还是有值的,这一点感觉有点问题,我们设置了反序列化应该忽略,不过它是在构造器上的,不是通过属性 setter 设置的,是不是也是可以接受的呢?晚点在 GitHub 上建一个 issue 看看大佬们的想法 - User4 为了避免前面构造器的问题,我们使用一个普通的 property 来测试,同样的为
UserId
设置 [property:JsonIgnore(Condition = JsonIgnoreCondition.WhenWriting)] 并为Description
设置 [property:JsonIgnore(Condition = JsonIgnoreCondition.WhenReading)] ,从输出结果可以看出此时我们的 Description 在反序列化的时候是被忽略的 - 目前使用 Source Generator 时也有一些类似的问题,并且 Generator 处理
WhenWriting
时有点问题,后续会进行修复,大家感兴趣可以尝试一下哈
More
新的 JsonIgnoreCondition 可以比较方便地只处理属性的序列化和反序列化时忽略,大家有类似的需求的话也可以尝试下哈
References
- .cs