簡體   English   中英

如何使用 JsonConverter 在 System.Text.Json.JsonSerializer.Serialize() 中排除屬性被序列化

[英]How to exclude a property from being serialized in System.Text.Json.JsonSerializer.Serialize() using a JsonConverter

我希望能夠在使用 System.Text.Json.JsonSerializer 進行序列化時排除屬性。 我不想在任何我想這樣做的地方使用JsonIgnore屬性。 我希望能夠通過某種當前不存在的 Fluent API 來定義我想僅在序列化期間排除的屬性。

我能找到的唯一選擇是定義一個JsonConverter並將其添加到我傳遞給 Serialize() 方法的JsonSerializerOptions上的轉換器列表中,如下所示:

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

在 JsonConverter 中,我必須自己使用Utf8JsonWriter編寫整個 JSON 表示,不包括我不想序列化的屬性。 僅僅能夠排除一個屬性需要做很多工作。 雖然 JsonConverter 是 .NET 團隊的一項出色的可擴展性功能,但對於我的用例而言,它的級別太低了。 有沒有人知道任何其他方式來實現財產的排除,而不必自己寫出 JSON 表示?

我不想做以下事情:

  • 使用屬性,或在運行時動態添加屬性
  • 將屬性的訪問修飾符更改為privateprotected
  • 使用第 3 方庫,因為如果我使用 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();
    }
}

選項 1 - 轉換為接口

  1. 提取描述所需 object 結構的接口。

     public interface IBook { public int Id { get; set; } public string Name { get; set; } }
  2. 在原版 class class Book: IBook

  3. 使用string Serialize(object value, Type inputType, JsonSerializerOptions options = null);的后續重載

    json = JsonSerializer.Serialize(book, typeof(IBook), options);

    如果要序列化Books數組(復數),則需要將typeof(IEnumerable<IBook>)作為參數傳遞。

選項 2 - 使用 AutoMapper

如果您無權訪問原始Book class,這將非常有用。

  1. 創建LiteBook class:

     public class LiteBook { public int Id { get; set; } public string Name { get; set; } }
  2. 創建映射配置:

     var config = new MapperConfiguration(cfg => { cfg.CreateMap<Book, LiteBook>(); });
  3. Map 並序列化

    json = JsonSerializer.Serialize(new Mapper(config).Map<LiteBook>(book), options)

因此,我偶然發現了一篇文章,該文章演示了如何在新的System.Text.Json命名空間中使用JsonDocument object,它是 Fluent ZDB974238714CA8DE634A7CE1D083A4 的下一個最佳選擇這是如何解決這個問題的。

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();
}

您可以簡單地忽略這樣的屬性:

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

參考: https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-ignore-properties?pivots=dotnet-6-0

您可以嘗試使用以下方法:

public static object ConvertToObjectWithoutListedProperties<T>(
                     this T objectToTransform,
                     string[] propertiesToIgnore)
{
    var type = objectToTransform.GetType();
    var returnClass = new ExpandoObject() as IDictionary<string, object>;
    foreach (var propertyInfo in type.GetProperties())
        if (!propertiesToIgnore.Contains(propertyInfo.Name))
            returnClass.Add(propertyInfo.Name,
                            propertyInfo.GetValue(objectToTransform));
    return returnClass;
}

致謝:“ 從 object 中刪除 null 屬性

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM