文章目录
简介
System.Text.Json 命名空间提供用于序列化和反序列化 JavaScript 对象表示法 (JSON) 的功能。 序列化是将对象状态(即其属性的值)转换为可存储或传输的形式的过程。 序列化形式不包含有关对象的关联方法的任何信息。 反序列化从序列化形式重新构造对象。
System.Text.Json
库的设计强调对广泛的功能集实现高性能和低内存分配。 内置的 UTF-8 支持可优化读写以 UTF-8 编码的 JSON 文本的过程,UTF-8 编码是针对 Web 上的数据和磁盘上的文件的最普遍的编码方式。
库还提供了用于处理内存中文档对象模型 (DOM) 的类。 此功能允许对 JSON 文件或字符串中的元素进行随机访问。
该库是作为 .NET Core 3.0 及更高版本共享框架的一部分内置的。 源生成功能内置在 .NET 6 和更高版本的共享框架中。
对于早于 .NET Core 3.0 的框架版本,请安装 System.Text.Json NuGet 包。 包支持以下框架:
- .NET Standard 2.0 及更高版本
- .NET Framework 4.6.2 及更高版本
- .NET Core 2.1 及更高版本
- .NET 5 及更高版本
https://learn.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json/overview
Asp .Net Core 如何配置 System.Text.Json
所有配置
https://learn.microsoft.com/zh-cn/dotnet/api/system.text.json.jsonserializeroptions?view=net-8.0&source=recommendations
AllowTrailingCommas | 获取或设置一个值,该值指示要反序列化的 JSON 有效负载中是否允许(和忽略)对象或数组中 JSON 值的列表末尾多余的逗号。 |
---|---|
Converters | 获取已注册的用户定义的转换器的列表。 |
Default | 获取使用默认配置的 的 JsonSerializerOptions 只读单一实例。 |
DefaultBufferSize | 获取或设置创建临时缓冲区时要使用的默认缓冲区大小(以字节为单位)。 |
DefaultIgnoreCondition | 获取或设置一个值,该值确定在序列化或反序列化期间何时忽略具有默认值的属性。 默认值为 Never。 |
DictionaryKeyPolicy | 获取或设置用于将 IDictionary 密钥名称转换为其他格式(如 camel 大小写)的策略。 |
Encoder | 获取或设置要在转义字符串时使用的编码器,或为 null (要使用默认编码器的话)。 |
IgnoreNullValues | **已过时。**获取或设置一个值,该值指示在序列化和反序列化期间是否 null 忽略值。 默认值为 false 。 |
IgnoreReadOnlyFields | 获取或设置一个值,该值指示在序列化期间是否忽略只读字段。 如果某字段用 readonly 关键字进行标记,则该字段为只读字段。 默认值为 false 。 |
IgnoreReadOnlyProperties | 获取一个值,该值指示在序列化期间是否忽略只读属性。 默认值为 false 。 |
IncludeFields | 获取或设置一个值,该值指示是否在序列化和反序列化期间处理字段。 默认值为 false 。 |
IsReadOnly | 获取一个值,该值指示当前实例是否已锁定以供用户修改。 |
MaxDepth | 获取或设置序列化或反序列化 JSON 时允许的最大深度,默认值 0 表示最大深度为 64。 |
NumberHandling | 获取或设置一个 对象,该对象指定序列化或反序列化时应如何处理数字类型。 |
PreferredObjectCreationHandling | 获取或设置反序列化 JSON 时属性的首选对象创建处理。 |
PropertyNameCaseInsensitive | 获取或设置一个值,该值指示属性名称在反序列化期间是否使用不区分大小写的比较。 默认值为 false 。 |
PropertyNamingPolicy | 获取或设置一个值,该值指定用于将对象的属性名称转换为其他格式(例如 camel 大小写)的策略;若为 null ,则保持属性名称不变。 |
ReadCommentHandling | 获取或设置一个值,该值定义反序列化过程中如何处理注释。 |
ReferenceHandler | 获取或设置一个 对象,该对象指定在读取和写入 JSON 时如何处理对象引用。 |
TypeInfoResolver | 获取或设置 JsonTypeInfo 此实例使用的协定解析程序。 |
TypeInfoResolverChain | 获取此实例使用的已 JsonTypeInfo 链接协定解析程序的列表。 |
UnknownTypeHandling | 获取或设置一个 对象,该对象指定如何在反序列化过程中反序列化声明为 Object 的类型。 |
UnmappedMemberHandling | 获取或设置一个 对象,该对象指定在反序列化对象类型时如何处理 JsonSerializer 无法映射到特定 .NET 成员的 JSON 属性。 |
WriteIndented | 获取或设置一个值,该值指示 JSON 是否应使用美观打印。 默认情况下,不使用任何额外的空白来序列化 JSON。 |
全局配置
在 AddControllers()
后面添加 AddJsonOptions
方法
builder.Services.AddControllers().AddJsonOptions(options=> {options.JsonSerializerOptions.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase;});
对比 Newtonsoft.Json
https://learn.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft?pivots=dotnet-8-0#table-of-differences
Newtonsoft.Json 功能 | System.Text.Json 等效 |
---|---|
默认情况下不区分大小写的反序列化 | ✔️ PropertyNameCaseInsensitive 全局设置 |
Camel 大小写属性名称 | ✔️ PropertyNamingPolicy 全局设置 |
对属性名称采用蛇形命名法 | ✔️ 蛇形命名法命名策略 |
最小字符转义 | ✔️ 严格字符转义,可配置 |
NullValueHandling.Ignore 全局设置 | ✔️ DefaultIgnoreCondition 全局选项 |
允许注释 | ✔️ ReadCommentHandling 全局设置 |
允许尾随逗号 | ✔️ AllowTrailingCommas 全局设置 |
自定义转换器注册 | ✔️ 优先级顺序不同 |
默认情况下无最大深度 | ✔️ 默认最大深度为 64,可配置 |
PreserveReferencesHandling 全局设置 | ✔️ ReferenceHandling 全局设置 |
序列化或反序列化带引号的数字 | ✔️ [NumberHandling 全局设置,JsonNumberHandling] 特性 |
反序列化为不可变类和结构 | ✔️ JsonConstructor,C# 9 记录 |
支持字段 | ✔️ [IncludeFields 全局设置,JsonInclude] 特性 |
DefaultValueHandling 全局设置 | ✔️ DefaultIgnoreCondition 全局设置 |
[JsonProperty] 上的 NullValueHandling 设置 | ✔️ JsonIgnore 特性 |
[JsonProperty] 上的 DefaultValueHandling 设置 | ✔️ JsonIgnore 特性 |
反序列化具有非字符串键的 Dictionary | ✔️ 受支持 |
支持非公共属性资源库和 Getter | ✔️ JsonInclude 特性 |
[JsonConstructor] 特性 | ✔️ [JsonConstructor] 特性 |
ReferenceLoopHandling 全局设置 | ✔️ ReferenceHandling 全局设置 |
回调 | ✔️ 回调 |
NaN、Infinity、-Infinity | ✔️ 受支持 |
[JsonProperty] 特性上的 Required 设置 | ✔️ [JsonRequired] 特性和 C# 必需的修饰符 |
DefaultContractResolver 用于忽略属性 | ✔️ DefaultJsonTypeInfoResolver 类 |
多态序列化 | ✔️ [JsonDerivedType] 特性 |
多态反序列化 | ✔️ [JsonDerivedType] 特性上的类型鉴别器 |
反序列化字符串枚举值 | ✔️ 反序列化字符串枚举值 |
MissingMemberHandling 全局设置 | ✔️ 处理缺少的成员 |
在没有资源库的情况下填充属性 | ✔️ 在没有资源库的情况下填充属性 |
ObjectCreationHandling 全局设置 | ✔️ 重用而不是替换属性 |
支持范围广泛的类型 | ⚠️ ⚠ |
将推断类型反序列化为 object 属性 | ⚠️ ⚠ |
将 JSON null 文本反序列化为不可为 null 的值类型 | ⚠️ ⚠ |
DateTimeZoneHandling 、DateFormatString 设置 | ⚠️ ⚠ |
JsonConvert.PopulateObject 方法 | ⚠️ ⚠ |
支持 System.Runtime.Serialization 特性 | ⚠️ ⚠ |
JsonObjectAttribute | ⚠️ ⚠ |
允许不带引号的属性名称 | ❌设计上不受支持 |
字符串值前后允许单引号 | ❌设计上不受支持 |
对字符串属性允许非字符串 JSON 值 | ❌设计上不受支持 |
TypeNameHandling.All 全局设置 | ❌设计上不受支持 |
支持 JsonPath 查询 | ❌不支持 |
可配置的限制 | ❌不支持 |
无实体类型下操作 Json
类似 Newtonsoft.Json,在没有实体类的情况下,也可以使用 JsonNode/JsonValue/JsonArray/JsonObject 操作 json。
自定义转换器
- DateTimeConverter - DateTime 类型转换器
- DateOnlyConverter - DateOnly 类型转换器
- TimeOnlyConverter - TimeOnly 类型转换器
- LongConverter - Long 类型转换器
- Int32Converter - Int 类型转换器
- DecimalConverter - Decimal 类型转换器
- StringConverter - String 类型转换器
- BooleanConverter - Boolean 类型转换器
- NullAbleConverter - 可空类型转换器
- EnumConverter - 枚举类型转换器
public class JsonConverterExtensions{/// <summary>/// DateTime类型转换器/// </summary>public sealed class DateTimeConverter : JsonConverter<DateTime>{/// <summary>/// 格式化/// </summary>public string Format { get; set; } = "yyyy-MM-dd HH:mm:ss";/// <summary>/// 使用默认格式,同: <c>System.Text.Json.JsonSerializer.Serialize(obj)</c>/// </summary>public DateTimeConverter() { }/// <summary>/// 指定格式化字符串/// </summary>public DateTimeConverter(string format){Format = format;}public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){if (reader.TokenType == JsonTokenType.Null)return default;if (string.IsNullOrEmpty(reader.GetString())){return default;}else{return DateTime.TryParse(reader.GetString(), out DateTime result) ? result : default;}}public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options){writer.WriteStringValue(value.ToString(Format, CultureInfo.InvariantCulture));}}/// <summary>/// DateOnly类型转换器/// </summary>public sealed class DateOnlyConverter : JsonConverter<DateOnly>{/// <summary>/// 格式化/// </summary>public string Format { get; set; } = "yyyy-MM-dd";/// <summary>/// 使用默认格式,同: <c>System.Text.Json.JsonSerializer.Serialize(obj)</c>/// </summary>public DateOnlyConverter() { }/// <summary>/// 指定格式化字符串/// </summary>public DateOnlyConverter(string format){Format = format;}public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){if (reader.TokenType == JsonTokenType.Null)return default;if (string.IsNullOrEmpty(reader.GetString())){return default;}else{return DateOnly.TryParse(reader.GetString(), out DateOnly result) ? result : default;}}public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options){writer.WriteStringValue(value.ToString(Format, CultureInfo.InvariantCulture));}}/// <summary>/// TimeOnly类型转换器/// </summary>public sealed class TimeOnlyConverter : JsonConverter<TimeOnly>{/// <summary>/// 格式化/// </summary>public string Format { get; set; } = "HH:mm:ss";/// <summary>/// 使用默认格式,同: <c>System.Text.Json.JsonSerializer.Serialize(obj)</c>/// </summary>public TimeOnlyConverter() { }/// <summary>/// 指定格式化字符串/// </summary>public TimeOnlyConverter(string format){Format = format;}public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){if (reader.TokenType == JsonTokenType.Null)return default;if (string.IsNullOrEmpty(reader.GetString())){return default;}else{return TimeOnly.TryParse(reader.GetString(), out TimeOnly result) ? result : default;}}public override void Write(Utf8JsonWriter writer, TimeOnly value, JsonSerializerOptions options){writer.WriteStringValue(value.ToString(Format, CultureInfo.InvariantCulture));}}/// <summary>/// Long类型转换器/// </summary>public sealed class LongConverter : JsonConverter<long>{public override long Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options){if (reader.TokenType == JsonTokenType.Null)return default;if (reader.TokenType == JsonTokenType.String){ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;if (Utf8Parser.TryParse(span, out long number, out int bytesConsumed) && span.Length == bytesConsumed)return number;if (long.TryParse(reader.GetString(), out number))return number;}return reader.GetInt64();}/// <summary>/// 注意这里在写入的时候转成了字符串/// </summary>/// <param name="writer"></param>/// <param name="value"></param>/// <param name="options"></param>public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options){writer.WriteStringValue(Convert.ToString(value));}}/// <summary>/// Int类型转换器/// </summary>public sealed class Int32Converter : JsonConverter<int>{public override int Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options){if (reader.TokenType == JsonTokenType.Null)return default;if (reader.TokenType == JsonTokenType.String){ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;if (Utf8Parser.TryParse(span, out int number, out int bytesConsumed) && span.Length == bytesConsumed)return number;if (int.TryParse(reader.GetString(), out number))return number;}return reader.GetInt32();}public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options){writer.WriteNumberValue(value);}}/// <summary>/// Decimal类型转换器/// </summary>public sealed class DecimalConverter : JsonConverter<decimal>{public override decimal Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options){if (reader.TokenType == JsonTokenType.String){ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;if (Utf8Parser.TryParse(span, out decimal number, out int bytesConsumed) && span.Length == bytesConsumed)return number;if (decimal.TryParse(reader.GetString(), out number))return number;}if (reader.TokenType == JsonTokenType.Null)return default;return reader.GetDecimal();}public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options){writer.WriteNumberValue(value);}}/// <summary>/// String类型转换器/// </summary>public sealed class StringConverter : JsonConverter<string>{public override string Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options){switch (reader.TokenType){case JsonTokenType.None:case JsonTokenType.Null:return null;case JsonTokenType.Number:return reader.GetDouble().ToString();case JsonTokenType.True:return "true";case JsonTokenType.False:return "false";default:return reader.GetString();}return reader.GetString();}public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options){writer.WriteStringValue(value);}}/// <summary>/// Boolean类型转换器/// </summary>public sealed class BooleanConverter : JsonConverter<bool>{public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){switch (reader.TokenType){case JsonTokenType.None:case JsonTokenType.Null:throw new Exception($"无法将 null 反序列化为 bool!");case JsonTokenType.Number:var d = reader.GetDouble();return !(d == 0);case JsonTokenType.String:var str = reader.GetString();if (string.Equals(str, "true", StringComparison.OrdinalIgnoreCase)) return true;else if (string.Equals(str, "false", StringComparison.OrdinalIgnoreCase)) return false;else throw new Exception($"无法将非 \"true\"或\"false\" 的字符串 转为 bool!");case JsonTokenType.True: return true;case JsonTokenType.False: return false;default: throw new Exception($"无法将 {reader.TokenType} 反序列化为 bool!");}}public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options){writer.WriteBooleanValue(value);}}/// <summary>/// 可空类型转换器/// </summary>public sealed class NullAbleConverter : JsonConverterFactory{/// <summary>/// 是否是Nullable类型的/// </summary>/// <param name="type"></param>private static bool IsNullable(Type type){if (type == null) return false;return type.Name == "Nullable`1";}private static ConcurrentDictionary<Type, JsonConverter> _cache = new ConcurrentDictionary<Type, JsonConverter>();public override bool CanConvert(Type typeToConvert){return IsNullable(typeToConvert);}public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options){return _cache.GetOrAdd(typeToConvert, (c) =>{return (JsonConverter)Activator.CreateInstance(typeof(NullAbleConverter<>).MakeGenericType(typeToConvert));});}}/// <summary>/// 泛型可空类型转换器/// </summary>/// <typeparam name="T"></typeparam>public sealed class NullAbleConverter<T> : JsonConverter<T>{/// <summary>/// 是否是Nullable类型的/// </summary>/// <param name="type"></param>private static bool IsNullable(Type type){if (type == null) return false;return type.Name == "Nullable`1";}public NullAbleConverter(){s_UnderlyingType = Nullable.GetUnderlyingType(typeof(T));}private Type s_UnderlyingType = null;public override bool CanConvert(Type typeToConvert){return IsNullable(typeToConvert);}public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){switch (reader.TokenType){case JsonTokenType.Null:case JsonTokenType.None:return default;case JsonTokenType.String:var str = reader.GetString();if (str == string.Empty) return default;return (T)JsonSerializer.Deserialize(ref reader, s_UnderlyingType, options);default:return (T)JsonSerializer.Deserialize(ref reader, s_UnderlyingType, options);}}public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options){if (value == null){writer.WriteStringValue("null");}else{JsonSerializer.Serialize(writer, value, value.GetType(), options);}}}/// <summary>/// 枚举类型转换器/// </summary>public sealed class EnumConverter : JsonConverterFactory{public EnumConverter(bool enum2String = true){this.enum2String = enum2String;}private static ConcurrentDictionary<Type, JsonConverter> _cache2String = new ConcurrentDictionary<Type, JsonConverter>();private static ConcurrentDictionary<Type, JsonConverter> _cache2Numer = new ConcurrentDictionary<Type, JsonConverter>();private readonly bool enum2String;public sealed override bool CanConvert(Type typeToConvert){return typeToConvert.IsEnum;}public sealed override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options){var _cache = enum2String ? _cache2String : _cache2Numer;return _cache.GetOrAdd(typeToConvert, (c) =>{var ctor = typeof(EnumConverter<>).MakeGenericType(typeToConvert).GetConstructor(new Type[] { typeof(bool) });return (JsonConverter)ctor.Invoke(new object[] { enum2String });});}}/// <summary>/// 泛型枚举类型转换器/// </summary>/// <typeparam name="T"></typeparam>public sealed class EnumConverter<T> : JsonConverter<T> where T : struct, Enum{public EnumConverter(bool enum2String){this.enum2String = enum2String;}private static readonly TypeCode s_enumTypeCode = Type.GetTypeCode(typeof(T));private readonly bool enum2String;public override bool CanConvert(Type type){return type.IsEnum;}public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){switch (reader.TokenType){case JsonTokenType.String:var str = reader.GetString();return (T)Enum.Parse(typeof(T), str, true);case JsonTokenType.Number:switch (s_enumTypeCode){case TypeCode.Int32:{if (reader.TryGetInt32(out var value8)){return Unsafe.As<int, T>(ref value8);}break;}case TypeCode.UInt32:{if (reader.TryGetUInt32(out var value4)){return Unsafe.As<uint, T>(ref value4);}break;}case TypeCode.UInt64:{if (reader.TryGetUInt64(out var value6)){return Unsafe.As<ulong, T>(ref value6);}break;}case TypeCode.Int64:{if (reader.TryGetInt64(out var value2)){return Unsafe.As<long, T>(ref value2);}break;}case TypeCode.SByte:{if (reader.TryGetSByte(out var value7)){return Unsafe.As<sbyte, T>(ref value7);}break;}case TypeCode.Byte:{if (reader.TryGetByte(out var value5)){return Unsafe.As<byte, T>(ref value5);}break;}case TypeCode.Int16:{if (reader.TryGetInt16(out var value3)){return Unsafe.As<short, T>(ref value3);}break;}case TypeCode.UInt16:{if (reader.TryGetUInt16(out var value)){return Unsafe.As<ushort, T>(ref value);}break;}}throw new Exception($"无法从 {JsonTokenType.Number} 转为枚举!");default:throw new Exception($"无法从 {reader.TokenType} 转为枚举!");}}public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options){if (enum2String){writer.WriteStringValue(value.ToString());}else{switch (s_enumTypeCode){case TypeCode.Int32:writer.WriteNumberValue(Unsafe.As<T, int>(ref value));break;case TypeCode.UInt32:writer.WriteNumberValue(Unsafe.As<T, uint>(ref value));break;case TypeCode.UInt64:writer.WriteNumberValue(Unsafe.As<T, ulong>(ref value));break;case TypeCode.Int64:writer.WriteNumberValue(Unsafe.As<T, long>(ref value));break;case TypeCode.Int16:writer.WriteNumberValue(Unsafe.As<T, short>(ref value));break;case TypeCode.UInt16:writer.WriteNumberValue(Unsafe.As<T, ushort>(ref value));break;case TypeCode.Byte:writer.WriteNumberValue(Unsafe.As<T, byte>(ref value));break;case TypeCode.SByte:writer.WriteNumberValue(Unsafe.As<T, sbyte>(ref value));break;default:throw new Exception($"无法将 {s_enumTypeCode} 序列化!");}}}}}
处理 Dynamic 类型
/// <summary>/// JsonElement转Dynamic类型/// </summary>public class JsonDynamicAccessor : DynamicObject{private readonly JsonElement _content;public JsonDynamicAccessor(JsonElement content){_content = content;}public override bool TryGetMember(GetMemberBinder binder, out dynamic result){if (_content.TryGetProperty(binder.Name, out JsonElement value)){result = Obtain(value);return true;}else{result = null;return false;}}private dynamic Obtain(in JsonElement element){switch (element.ValueKind){case JsonValueKind.String: return element.GetString();case JsonValueKind.Null: return null;case JsonValueKind.False: return false;case JsonValueKind.True: return true;case JsonValueKind.Number:if (element.TryGetInt64(out long longNumber)){return longNumber;}if (element.TryGetInt32(out int intNumber)){return intNumber;}if (element.TryGetDecimal(out decimal decimalNumber)){return decimalNumber;}if (element.TryGetDouble(out double doubleNumber)){return doubleNumber;}if (element.TryGetInt16(out short shortNumber)){return shortNumber;}break;default: break;}if (element.ValueKind == JsonValueKind.Array){return element.EnumerateArray().Select(item => Obtain(item)).ToList();}else{return new JsonDynamicAccessor(element);}}}
封装常用配置
/// <summary>/// Json序列化扩展/// </summary>public static class JsonSerializeExtensions{public static IMvcBuilder AddMCodeJsonOptions(this IMvcBuilder builder,Action<JsonOptions> configure = null){builder.AddJsonOptions(options =>{// 设置要在转义字符串时使用的编码器,或为 null(要使用默认编码器的话)options.JsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; // 非ascii码转换// 是否在序列化和反序列化期间处理字段,默认值为 falseoptions.JsonSerializerOptions.IncludeFields = true;// 在序列化期间是否忽略只读字段.如果某字段用 readonly 关键字进行标记,则该字段为只读字段。 默认值为 falseoptions.JsonSerializerOptions.IgnoreReadOnlyFields = false;// 在序列化或反序列化期间何时忽略具有默认值的属性,默认值:Never属性总是被序列化和反序列化,与IgnoreNullValues配置无关。// WhenWritingNull:(如果其值为空,则忽略属性。这只应用于引用类型的属性和字段)options.JsonSerializerOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.Never;// 指示属性名称在反序列化期间是否使用不区分大小写的比较,默认值为 falseoptions.JsonSerializerOptions.PropertyNameCaseInsensitive = true;// 指定用于将对象的属性名称转换为其他格式(例如 camel 大小写)的策略;若为 null,则保持属性名称不变。options.JsonSerializerOptions.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase;// 反序列化过程中如何处理注释options.JsonSerializerOptions.ReadCommentHandling = System.Text.Json.JsonCommentHandling.Skip;// 该值指示要反序列化的 JSON 有效负载中是否允许(和忽略)对象或数组中 JSON 值的列表末尾多余的逗号。options.JsonSerializerOptions.AllowTrailingCommas = true;//允许 {"Prop":"NaN"} 浮点型,但不允许 {\"Prop\":NaN},这点无法做到与Newtonsoft兼容options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.AllowNamedFloatingPointLiterals;// 是否格式化文本options.JsonSerializerOptions.WriteIndented = true;// 处理循环引用类型options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;options.JsonSerializerOptions.Converters.Add(new JsonConverterExtensions.DateTimeConverter());options.JsonSerializerOptions.Converters.Add(new JsonConverterExtensions.DateOnlyConverter());options.JsonSerializerOptions.Converters.Add(new JsonConverterExtensions.TimeOnlyConverter());options.JsonSerializerOptions.Converters.Add(new JsonConverterExtensions.LongConverter());options.JsonSerializerOptions.Converters.Add(new JsonConverterExtensions.Int32Converter());options.JsonSerializerOptions.Converters.Add(new JsonConverterExtensions.DecimalConverter());options.JsonSerializerOptions.Converters.Add(new JsonConverterExtensions.BooleanConverter()); ;options.JsonSerializerOptions.Converters.Add(new JsonConverterExtensions.StringConverter());options.JsonSerializerOptions.Converters.Add(new JsonConverterExtensions.EnumConverter());options.JsonSerializerOptions.Converters.Add(new JsonConverterExtensions.NullAbleConverter());configure.Invoke(options);});return builder;}}builder.Services.AddControllers().AddMCodeJsonOptions();
封装 JsonHelper 帮助类
/// <summary>/// Json序列化反序列化类/// </summary>public class JsonHelper{public static JsonSerializerOptions DefaultSerializerOptions{get{var options = new JsonSerializerOptions();// 设置要在转义字符串时使用的编码器,或为 null(要使用默认编码器的话)options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;// 是否在序列化和反序列化期间处理字段,默认值为 falseoptions.IncludeFields = true;// 在序列化期间是否忽略只读字段.如果某字段用 readonly 关键字进行标记,则该字段为只读字段。 默认值为 falseoptions.IgnoreReadOnlyFields = false;// 在序列化或反序列化期间何时忽略具有默认值的属性,默认值:Never属性总是被序列化和反序列化,与IgnoreNullValues配置无关。// WhenWritingNull:(如果其值为空,则忽略属性。这只应用于引用类型的属性和字段)options.DefaultIgnoreCondition = JsonIgnoreCondition.Never;// 指示属性名称在反序列化期间是否使用不区分大小写的比较,默认值为 falseoptions.PropertyNameCaseInsensitive = true;// 指定用于将对象的属性名称转换为其他格式(例如 camel 大小写)的策略;若为 null,则保持属性名称不变。options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;// 反序列化过程中如何处理注释options.ReadCommentHandling = JsonCommentHandling.Skip;// 该值指示要反序列化的 JSON 有效负载中是否允许(和忽略)对象或数组中 JSON 值的列表末尾多余的逗号。options.AllowTrailingCommas = true;//允许 {"Prop":"NaN"} 浮点型,但不允许 {\"Prop\":NaN},这点无法做到与Newtonsoft兼容options.NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.AllowNamedFloatingPointLiterals;// 是否格式化文本options.WriteIndented = true;// 处理循环引用类型options.ReferenceHandler = ReferenceHandler.IgnoreCycles;options.Converters.Add(new JsonConverterExtensions.DateTimeConverter());options.Converters.Add(new JsonConverterExtensions.DateOnlyConverter());options.Converters.Add(new JsonConverterExtensions.TimeOnlyConverter());options.Converters.Add(new JsonConverterExtensions.LongConverter());options.Converters.Add(new JsonConverterExtensions.Int32Converter());options.Converters.Add(new JsonConverterExtensions.DecimalConverter());options.Converters.Add(new JsonConverterExtensions.BooleanConverter()); ;options.Converters.Add(new JsonConverterExtensions.StringConverter());options.Converters.Add(new JsonConverterExtensions.EnumConverter());options.Converters.Add(new JsonConverterExtensions.NullAbleConverter());return options;}}public static T Deserialize<T>(string json, JsonSerializerOptions serializerOptions = null){if (string.IsNullOrEmpty(json)) return default;if (serializerOptions == null) serializerOptions = DefaultSerializerOptions;//值类型和String类型if (typeof(T).IsValueType || typeof(T) == typeof(string)){return (T)Convert.ChangeType(json, typeof(T));}// dynamic类型if (typeof(T) == typeof(object)){return (dynamic)new JsonDynamicAccessor(JsonSerializer.Deserialize<JsonElement>(json));}return JsonSerializer.Deserialize<T>(json, serializerOptions);}public static string Serialize<T>(T obj, JsonSerializerOptions serializerOptions = null){if (obj is null) return string.Empty;if (obj is string) return obj.ToString();if (serializerOptions == null) serializerOptions = DefaultSerializerOptions;return JsonSerializer.Serialize(obj, serializerOptions);}