admin管理员组

文章数量:1028841

dotnet 10 新的 JsonIgnoreCondition

dotnet 10 新的 JsonIgnoreCondition

Intro

之前提了一个 api 建议为 JsonIgnore 添加两个扩展,WhenReadingWhenWriting,主要的一个用例是 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 因为添加了 WhenWritingJsonIgnoreCondition 的,在序列化的时候被忽略了,只有 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 测试示例如下:

代码语言:javascript代码运行次数:0运行复制
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
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-24,如有侵权请联系 cloudcommunity@tencent 删除var测试序列化迁移console

dotnet 10 新的 JsonIgnoreCondition

dotnet 10 新的 JsonIgnoreCondition

Intro

之前提了一个 api 建议为 JsonIgnore 添加两个扩展,WhenReadingWhenWriting,主要的一个用例是 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 因为添加了 WhenWritingJsonIgnoreCondition 的,在序列化的时候被忽略了,只有 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 测试示例如下:

代码语言:javascript代码运行次数:0运行复制
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
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-24,如有侵权请联系 cloudcommunity@tencent 删除var测试序列化迁移console

本文标签: dotnet 10 新的 JsonIgnoreCondition