如何使用 JsonConverter 在 System.Text.Json.JsonSerializer.Serialize() 中排除属性被序列化
Posted
技术标签:
【中文标题】如何使用 JsonConverter 在 System.Text.Json.JsonSerializer.Serialize() 中排除属性被序列化【英文标题】:How to exclude a property from being serialized in System.Text.Json.JsonSerializer.Serialize() using a JsonConverter 【发布时间】:2020-02-22 06:59:16 【问题描述】:我希望能够在使用 System.Text.Json.JsonSerializer 进行序列化时排除属性。我不想在任何我想这样做的地方使用JsonIgnore
属性。我希望能够通过某种目前不存在的 Fluent API 来定义我想在序列化期间排除的属性。
我能找到的唯一选择是定义一个 JsonConverter
并将其添加到 JsonSerializerOptions
上的转换器列表中,我将其传递给 Serialize() 方法,如下所示:
var options = new JsonSerializerOptions();
options.Converters.Add(new BookConverter());
json = JsonSerializer.Serialize(book, options);
在 JsonConverter 中,我必须自己使用 Utf8JsonWriter
编写整个 JSON 表示,不包括我不想序列化的属性。仅仅能够排除一个属性需要做很多工作。虽然 JsonConverter 是 .NET 团队的一项出色的可扩展性功能,但对于我的用例而言,它的级别太低了。有谁知道无需自己写出 JSON 表示即可排除该属性的任何其他方法?
我不想做以下事情:
使用属性,或在运行时动态添加属性 将属性的访问修饰符更改为private
或 protected
使用 3rd 方库,因为如果我使用 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 - 转换为接口
描述所需对象结构的提取接口。
public interface IBook
public int Id get; set;
public string Name get; set;
在原类class Book : IBook
上实现它
使用string Serialize(object value, Type inputType, JsonSerializerOptions options = null);
的跟随重载
json = JsonSerializer.Serialize(book, typeof(IBook), options);
如果您要序列化 Books
(复数)的数组,则需要将 typeof(IEnumerable<IBook>)
作为参数传递。
选项 2 - 使用 AutoMapper
如果您无权访问原始 Book
类,这很有用。
创建LiteBook
类:
public class LiteBook
public int Id get; set;
public string Name get; set;
创建映射配置:
var config = new MapperConfiguration(cfg =>
cfg.CreateMap<Book, LiteBook>();
);
映射并序列化
json = JsonSerializer.Serialize(new Mapper(config).Map<LiteBook>(book), options)
【讨论】:
MapperConfiguration
的命名空间是什么?【参考方案2】:
所以我偶然发现了一篇文章,该文章演示了如何在新的 System.Text.Json
命名空间中使用 JsonDocument
对象,它是 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();
【讨论】:
这行得通,但如果它应该运行得很快,性能就不那么好了。value
在被解析为JsonDocument
之前以默认方式序列化,只有这样我们才能真正开始手动序列化(支持忽略属性)该值。所以执行成本几乎翻了2-2.5倍。【参考方案3】:
您可以简单地忽略这样的属性:
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
【讨论】:
以上是关于如何使用 JsonConverter 在 System.Text.Json.JsonSerializer.Serialize() 中排除属性被序列化的主要内容,如果未能解决你的问题,请参考以下文章
冻结了如何在***模型上分配我自己的 JsonConverter?
如何在 JSON.NET 中实现自定义 JsonConverter?
如何在 .net core 3.1 中的 Newtonsoft JsonConverter 中注入依赖项
.net HttpClient 与自定义 JsonConverter