[英]C# .Net Core 3.1 System.Text.Json Ignore empty collection in serialization
Using Newtonsoft we had a custom resolver for ignoring empty collections.使用 Newtonsoft,我们有一个自定义解析器来忽略空的 collections。 Is there any equivalent configuration for the new system.text.json in.Net core 3.1
新的system.text.json in.Net core 3.1是否有任何等效配置
Conditionally ignore a property from .NET5's official How to migrate from Newtonsoft.Json to System.Text.Json from 2020 Dec 14 states: 有条件地忽略.NET5 的官方属性How to migrate from Newtonsoft.Json to System.Text.Json from 2020 Dec 14 指出:
System.Text.Json provides the following ways to ignore properties or fields while serializing:
System.Text.Json 提供了以下方法来在序列化时忽略属性或字段:
- The [JsonIgnore] attribute (...).
[JsonIgnore] 属性 (...)。
- The IgnoreReadOnlyProperties global option (...).
IgnoreReadOnlyProperties 全局选项 (...)。
- (...) JsonSerializerOptions.IgnoreReadOnlyFields global (...)
(...) JsonSerializerOptions.IgnoreReadOnlyFields 全局 (...)
- The DefaultIgnoreCondition global option lets you ignore all value type properties that have default values, or ignore all reference type properties that have null values.
DefaultIgnoreCondition 全局选项允许您忽略所有具有默认值的值类型属性,或忽略所有具有空值的引用类型属性。
These options don't let you:
这些选项不允许您:
- Ignore selected properties based on arbitrary criteria evaluated at run time.
忽略基于运行时评估的任意标准的选定属性。
For that functionality, you can write a custom converter.
对于该功能,您可以编写自定义转换器。 Here's a sample POCO and a custom converter for it that illustrates this approach:
这是一个示例 POCO 和一个自定义转换器,用于说明这种方法:
(An example of a custom converter for a type follows)
(类型的自定义转换器示例如下)
Please note that this converter needs to be a converter for the type that contains the property that is a collection, it's not a converter for the collection type (for that see my 2nd answer).请注意,此转换器必须是包含集合属性的类型的转换器,它不是集合类型的转换器(请参阅我的第二个答案)。
I know that this is not what you're after but maybe someone could build on this or there is a very very slim chance that it may suit some scenarios.我知道这不是你想要的,但也许有人可以以此为基础,或者它可能适合某些场景的可能性非常小。
An object new A()
of一个对象
new A()
的
public class A
{
public List<int> NullList {get;set;}
public List<int> EmptyList {get;set;} = new List<int>();
};
becomes变成
{
"EmptyList": null
}
How to write custom converters for JSON serialization (marshalling) in .NET from 2021 Feb 25 in Custom converter patterns says: How to write custom converters for JSON serialization (marshalling) in .NET from 2021 Feb 25 in Custom converter patterns说:
There are two patterns for creating a custom converter: the basic pattern and the factory pattern.
创建自定义转换器有两种模式:基本模式和工厂模式。 The factory pattern is for converters that handle type Enum or open generics.
工厂模式适用于处理 Enum 类型或开放泛型的转换器。 The basic pattern is for non-generic and closed generic types.
基本模式适用于非泛型和封闭泛型类型。 For example, converters for the following types require the factory pattern:
例如,以下类型的转换器需要工厂模式:
- Dictionary<TKey,TValue>
字典<TKey,TValue>
- Enum
枚举
- List
列表
Some examples of types that can be handled by the basic pattern include:
可以由基本模式处理的类型的一些示例包括:
- Dictionary<int, string>
字典<整数,字符串>
- WeekdaysEnum
工作日枚举
- List
列表
- DateTime
约会时间
- Int32
整数32
The basic pattern creates a class that can handle one type.
基本模式创建了一个可以处理一种类型的类。 The factory pattern creates a class that determines, at run time, which specific type is required and dynamically creates the appropriate converter.
工厂模式创建一个类,该类在运行时确定需要哪种特定类型并动态创建适当的转换器。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
#nullable disable
namespace Sandbox4
{
public class A
{
public List<int> NullList {get;set;}
public List<int> EmptyList {get;set;} = new List<int>();
};
public class Program
{
public static void Main()
{
A a = new ();
JsonSerializerOptions options = new ()
{
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault,
WriteIndented = true,
Converters =
{
new IEnumerableTConverter()
}
};
string aJson =
JsonSerializer.Serialize<A>(a, options);
Console.WriteLine(aJson);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Sandbox4
{
// Modified DictionaryTEnumTValueConverter
// from https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-5-0#custom-converter-patterns
public class IEnumerableTConverter : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType)
{
return false;
}
var realType = typeToConvert.GetGenericTypeDefinition();
if (realType.IsAssignableTo(typeof(IEnumerable<>)))
{
return false;
}
return true;
}
public override JsonConverter CreateConverter(
Type type,
JsonSerializerOptions options)
{
Type generictype = type.GetGenericArguments()[0];
JsonConverter converter = (JsonConverter)Activator.CreateInstance(
typeof(ICollectionTConverterInner<,>).MakeGenericType(
new Type[] { type, generictype }),
BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: new object[] { type, options },
culture: null);
return converter;
}
private class ICollectionTConverterInner<T,U> :
JsonConverter<T> where T: IEnumerable<U>
{
private readonly JsonConverter<T> _normalConverter;
public ICollectionTConverterInner(Type type,JsonSerializerOptions options)
{
// For performance, use the existing converter if available.
var existing = new JsonSerializerOptions().GetConverter(type);
if( existing == null ) throw new ApplicationException($"Standard converter for {type} not found.");
_normalConverter = (JsonConverter<T>) existing;
}
public override T Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
// Untested
return _normalConverter.Read(ref reader, typeToConvert, options);
}
public override void Write(
Utf8JsonWriter writer,
T collection,
JsonSerializerOptions options)
{
if(!collection.Any())
{
writer.WriteNullValue();
return;
}
_normalConverter.Write(writer, collection, options);
}
}
}
}
TypeInfoResolver
added in .NET 7(accessible in older runtimes via the system.text.json nuget package, pre-release as of time of this answer) allows this. TypeInfoResolver
added in .NET 7(accessible in older runtimes via the system.text.json nuget package, pre-release as of time of this answer) allows this.
Example:例子:
using System.Collections;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
public class TestObject {
public List<int> Ints { get; } = new() {3, 4, 5};
public List<int> EmptyInts { get; } = new();
public List<int> NullInts { get; }
}
public static class Program {
public static void Main() {
var options = new JsonSerializerOptions {
TypeInfoResolver = new DefaultJsonTypeInfoResolver {
Modifiers = {DefaultValueModifier}
},
};
var obj = new TestObject();
var text = JsonSerializer.Serialize(obj, options);
Console.WriteLine(text);
}
private static void DefaultValueModifier(JsonTypeInfo type_info) {
foreach (var property in type_info.Properties) {
if (typeof(ICollection).IsAssignableFrom(property.PropertyType)) {
property.ShouldSerialize = (_, val) => val is ICollection collection && collection.Count > 0;
}
}
}
}
output: output:
{"Ints":[3,4,5]}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.