Asp .Net Core 系列:Asp .Net Core 配置 System.Text.Json

来自:博客园
时间:2024-01-30
阅读:

 

简介

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 的值类型 ⚠️ ⚠
DateTimeZoneHandlingDateFormatString 设置 ⚠️ ⚠
JsonConvert.PopulateObject 方法 ⚠️ ⚠
支持 System.Runtime.Serialization 特性 ⚠️ ⚠
JsonObjectAttribute ⚠️ ⚠
允许不带引号的属性名称 设计上不受支持
字符串值前后允许单引号 设计上不受支持
对字符串属性允许非字符串 JSON 值 设计上不受支持
TypeNameHandling.All 全局设置 设计上不受支持
支持 JsonPath 查询 不支持
可配置的限制 不支持

无实体类型下操作 Json

类似 Newtonsoft.Json,在没有实体类的情况下,也可以使用 JsonNode/JsonValue/JsonArray/JsonObject 操作 json。

Asp .Net Core 系列:Asp .Net Core 配置 System.Text.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码转换
                 // 是否在序列化和反序列化期间处理字段,默认值为 false
                 options.JsonSerializerOptions.IncludeFields = true;
                 // 在序列化期间是否忽略只读字段.如果某字段用 readonly 关键字进行标记,则该字段为只读字段。 默认值为 false
                 options.JsonSerializerOptions.IgnoreReadOnlyFields = false;
                 // 在序列化或反序列化期间何时忽略具有默认值的属性,默认值:Never属性总是被序列化和反序列化,与IgnoreNullValues配置无关。
                 // WhenWritingNull:(如果其值为空,则忽略属性。这只应用于引用类型的属性和字段)
                 options.JsonSerializerOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.Never;
                 // 指示属性名称在反序列化期间是否使用不区分大小写的比较,默认值为 false
                 options.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;
                // 是否在序列化和反序列化期间处理字段,默认值为 false
                options.IncludeFields = true;
                // 在序列化期间是否忽略只读字段.如果某字段用 readonly 关键字进行标记,则该字段为只读字段。 默认值为 false
                options.IgnoreReadOnlyFields = false;
                // 在序列化或反序列化期间何时忽略具有默认值的属性,默认值:Never属性总是被序列化和反序列化,与IgnoreNullValues配置无关。
                // WhenWritingNull:(如果其值为空,则忽略属性。这只应用于引用类型的属性和字段)
                options.DefaultIgnoreCondition = JsonIgnoreCondition.Never;
                // 指示属性名称在反序列化期间是否使用不区分大小写的比较,默认值为 false
                options.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);
        }
返回顶部
顶部