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

簡介

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。

image

自定義轉換器

  • 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
    {
        private static readonly JsonSerializerOptions _defaultSerializerOptions;

        static JsonHelper()
        {
            var options = new JsonSerializerOptions();

            // 設置要在轉義字符串時使用的編碼器,或爲 null(要使用默認編碼器的話)
            options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
            // 是否在序列化和反序列化期間處理字段,默認值爲 false
            options.IncludeFields = true;
            // 在序列化期間是否忽略只讀字段.如果某字段用 readonly 關鍵字進行標記,則該字段爲只讀字段。 默認值爲 false
            options.IgnoreReadOnlyFields = false;
            // 在序列化或反序列化期間何時忽略具有默認值的屬性,默認值:Never屬性總是被序列化和反序列化,與IgnoreNullValues配置無關。
            // WhenWritingNull:(如果其值爲空,則忽略屬性。這隻應用於引用類型的屬性和字段)
            options.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.Never;
            // 指示屬性名稱在反序列化期間是否使用不區分大小寫的比較,默認值爲 false
            options.PropertyNameCaseInsensitive = true;
            // 指定用於將對象的屬性名稱轉換爲其他格式(例如 camel 大小寫)的策略;若爲 null,則保持屬性名稱不變。
            options.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase;
            // 反序列化過程中如何處理註釋
            options.ReadCommentHandling = System.Text.Json.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());
            _defaultSerializerOptions = 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);
        }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章