![](/img/trans.png)
[英]System.Text.Json access Json object of json object using c# .net core 3.1
[英]C# .Net Core 3.1 System.Text.Json Ignore empty collection in serialization
使用 Newtonsoft,我們有一個自定義解析器來忽略空的 collections。 新的system.text.json in.Net core 3.1是否有任何等效配置
有條件地忽略.NET5 的官方屬性How to migrate from Newtonsoft.Json to System.Text.Json from 2020 Dec 14 指出:
System.Text.Json 提供了以下方法來在序列化時忽略屬性或字段:
- [JsonIgnore] 屬性 (...)。
- IgnoreReadOnlyProperties 全局選項 (...)。
- (...) JsonSerializerOptions.IgnoreReadOnlyFields 全局 (...)
- DefaultIgnoreCondition 全局選項允許您忽略所有具有默認值的值類型屬性,或忽略所有具有空值的引用類型屬性。
這些選項不允許您:
- 忽略基於運行時評估的任意標准的選定屬性。
對於該功能,您可以編寫自定義轉換器。 這是一個示例 POCO 和一個自定義轉換器,用於說明這種方法:
(類型的自定義轉換器示例如下)
請注意,此轉換器必須是包含集合屬性的類型的轉換器,它不是集合類型的轉換器(請參閱我的第二個答案)。
我知道這不是你想要的,但也許有人可以以此為基礎,或者它可能適合某些場景的可能性非常小。
一個對象new A()
的
public class A
{
public List<int> NullList {get;set;}
public List<int> EmptyList {get;set;} = new List<int>();
};
變成
{
"EmptyList": null
}
How to write custom converters for JSON serialization (marshalling) in .NET from 2021 Feb 25 in Custom converter patterns說:
創建自定義轉換器有兩種模式:基本模式和工廠模式。 工廠模式適用於處理 Enum 類型或開放泛型的轉換器。 基本模式適用於非泛型和封閉泛型類型。 例如,以下類型的轉換器需要工廠模式:
- 字典<TKey,TValue>
- 枚舉
- 列表
可以由基本模式處理的類型的一些示例包括:
- 字典<整數,字符串>
- 工作日枚舉
- 列表
- 約會時間
- 整數32
基本模式創建了一個可以處理一種類型的類。 工廠模式創建一個類,該類在運行時確定需要哪種特定類型並動態創建適當的轉換器。
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.
例子:
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:
{"Ints":[3,4,5]}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.