一尘不染

如何使用JsonConverter从System.Text.Json.JsonSerializer.Serialize()中排除要序列化的属性

json

我希望能够在使用System.Text.Json.JsonSerializer进行序列化时排除属性。我不想在JsonIgnore每个我想做的地方都使用属性。我希望能够通过某种Fluent
API定义仅在序列化过程中要排除的属性,目前尚不存在。

我能够找到的唯一选择是定义一个JsonConverter,并将其添加到JsonSerializerOptions我传递给Serialize()方法的的Converters列表中,如下所示:

var options = new JsonSerializerOptions();
options.Converters.Add(new BookConverter());
json = JsonSerializer.Serialize(book, options);

在JsonConverter中,我必须使用自己编写整个JSON表示形式Utf8JsonWriter,但不包括我不想序列化的属性。仅仅能够排除一个属性,这是很多工作。尽管JsonConverter是.NET团队的一项出色的可扩展性功能,但对于我的用例而言,它只是太底层了。有谁知道有其他方法可以实现排除属性,而不必亲自写出JSON表示形式?

我不想执行以下操作:

  • 使用属性,或在运行时动态添加属性
  • 将属性的访问修饰符更改为privateprotected
  • 使用3rd party库,因为如果使用Json.NET,我的问题就可以解决。

例:

class Program
{
    void Main()
    {
        // We want to serialize Book but to ignore the Author property
        var book = new Book() { Id = 1, Name = "Calculus", Author = new Author() };

        var json = JsonSerializer.Serialize(book);
        // Default serialization, we get this:
        // json = { "Id": 1, "Name": "Calculus", "Author": {} }

        // Add our custom converter to options and pass it to the Serialize() method
        var options = new JsonSerializerOptions();
        options.Converters.Add(new BookConverter());
        json = JsonSerializer.Serialize(book, options);
        // I want to get this:
        // json = { Id: 1, Name: "Calculus" }
    }
}

public class Author { }

public class Book
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Author Author { get; set; }
}

public class BookConverter : JsonConverter<Book>
{
    public override Book Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // Use default implementation when deserializing (reading)
        return JsonSerializer.Deserialize<Book>(ref reader, options);
    }

    public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
    {
        // Serializing. Here we have to write the JSON representation ourselves
        writer.WriteStartObject();

        writer.WriteNumber("Id", value.Id);
        writer.WriteString("Name", value.Name);
        // Don't write Author so we can exclude it

        writer.WriteEndObject();
    }
}

阅读 1007

收藏
2020-07-27

共1个答案

一尘不染

因此,我偶然发现了一篇文章,该文章演示了如何JsonDocument在新System.Text.Json名称空间中使用该对象,这是Fluent
API的第二大优点。这是解决这个问题的方法。

BookConverter.Write()方法:

public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
{
    writer.WriteStartObject();

    using (JsonDocument document = JsonDocument.Parse(JsonSerializer.Serialize(value)))
    {
        foreach (var property in document.RootElement.EnumerateObject())
        {
            if (property.Name != "Author")
                property.WriteTo(writer);
        }
    }

    writer.WriteEndObject();
}
2020-07-27