System.Text.Json类库进行json转化时ValueKind:Object问题

当你的使用的Json库是System.Text.Json,而不是Newtonsoft.Json库的时候,你可能遇到以下问题及其解决办法。通常的解决办法是进行一些对应的配置。此外就需要根据情况使用自定义转换器实现你的需求。以下是通常遇到的使用自定义转换器解决的例子:

Q1.当遇到System.InvalidCastException:"Unable to cast object of type 'System.Text.Json.JsonElement' to type 'System.Int32'."这种错误的时候,是由于System.Text.Json类库进行json转化时,没有明确类型的基础类型导致的。通常可能是某一个属性类型使用object情况。

A1:解决办法是写一个 对象Json转换器 类,如下所示:

csharp 复制代码
  /// <summary>
 /// 对象Json转化器
 /// </summary>
 public class ObjectJsonConverter : JsonConverter<Object>
 {
     public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
     {
         switch (reader.TokenType)
         {
             case JsonTokenType.String:
                 if (DateTime.TryParse(reader.GetString(), out DateTime dateTime))
                     return dateTime;
                 return reader.GetString();
             case JsonTokenType.Number:
                 if (reader.TryGetInt32(out int intValue))
                     return intValue;
                 else if (reader.TryGetDouble(out double doubleValue))
                     return doubleValue;
                 else if (reader.TryGetDecimal(out decimal decimalValue))
                     return decimalValue;
                 throw new JsonException("Unsupported number format");
             case JsonTokenType.True:
                 return true;
             case JsonTokenType.False:
                 return false;
             case JsonTokenType.Null:
                 return null;
             case JsonTokenType.StartObject:
                 return JsonSerializer.Deserialize<JsonElement>(ref reader, options);
             case JsonTokenType.StartArray:
                 return JsonSerializer.Deserialize<JsonElement[]>(ref reader, options);
             default:
                 throw new JsonException($"Unexpected token type: {reader.TokenType}");
         }
     }

     public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
     {
         if (value == null) writer.WriteNullValue();
         else if ((value is string || value is DateTime || value is Guid)) writer.WriteStringValue(value.ToString());
         else if (value is int intValue) writer.WriteNumberValue(intValue);
         else if (value is double doubleValue) writer.WriteNumberValue(doubleValue);
         else if (value is decimal decimalValue) writer.WriteNumberValue(decimalValue);
         else if (value is char charValue) writer.WriteNumberValue(charValue);
         else if (value is bool boolValue) writer.WriteBooleanValue(boolValue);
         else if (value is JsonElement jsonElement) jsonElement.WriteTo(writer);
         else if (value is JsonElement[] jsonElements)
         {
             writer.WriteStartArray();
             foreach (var element in jsonElements)
             {
                 element.WriteTo(writer);
             }
             writer.WriteEndArray();
         }
         else JsonSerializer.Serialize(writer, value, value.GetType(), options);
     }
 }

使用如下:

csharp 复制代码
builder.Services.AddJsonOptions(options =>
{
    // 添加Object格式化转换器
    options.JsonSerializerOptions.Converters.Add(new ObjectJsonConverter());
});

Q2:在webapi接口返回结果中,时间属性的值返回的形式如:"2024-01-01T10:00:00",而我们想要的是不带T的格式,比如"2024-01-01 10:00:00"这种。

A2:需要定义一个时间Json转换器DateTimeJsonConverter,代码如下:

csharp 复制代码
 /// <summary>
	/// 设置Json默认DateTime格式化
	/// </summary>
	public class DateTimeJsonConverter : JsonConverter<DateTime>
 {
     private readonly string _format;
     public DateTimeJsonConverter(string format)
     {
         _format = format;
     }
     public override void Write(Utf8JsonWriter writer, DateTime dateTime, JsonSerializerOptions options)
     {
         writer.WriteStringValue(dateTime.ToString(_format));
     }
     public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
     {
         if (reader.TokenType == JsonTokenType.String)
         {
             if (DateTime.TryParse(reader.GetString(), out DateTime dateTime))
                 return dateTime;
         }
         return reader.GetDateTime();
     }
 }

使用如下:

csharp 复制代码
builder.Services.AddJsonOptions(options =>
{
     // 添加时间格式化转换器
 options.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss"));
});

通常完整一点的配置如下:

csharp 复制代码
builder.Services.AddJsonOptions(options =>
{
    // 设置编码格式
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
// 是否格式化文本
options.JsonSerializerOptions.WriteIndented = true;
//不区分大小写
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;//不区分大小写
// 字段采用驼峰式命名
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
// 忽略null值
//options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
// 忽略只读字段
//options.JsonSerializerOptions.IgnoreReadOnlyProperties = true;
// 对字典的键进行驼峰命名
options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
//不允许有注释的不标准json
options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Disallow;
// 允许属性值末尾存在逗号
options.JsonSerializerOptions.AllowTrailingCommas = true;
// 处理循环引用类型
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
//枚举类型转string配置(避免转int)
//options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
// 添加时间格式化转换器
options.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss"));
// 添加Object格式化转换器
options.JsonSerializerOptions.Converters.Add(new ObjectJsonConverter());
});

Q3:遇到枚举的属性,如果想在接口返回的时候不返回数字,而想返回字符串的情况

A3:在配置的时候进行如下配置即可:

csharp 复制代码
builder.Services.AddJsonOptions(options =>
{
     //枚举类型转string配置(避免转int)
	options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});

此外在枚举的地方添加JsonConverter(typeof(JsonStringEnumConverter))特性即可返回字符串,代码如下:

csharp 复制代码
 public class Sample
 {
     public int Id { get; set; }
     public object  Value { get; set; }
     [JsonConverter(typeof(JsonStringEnumConverter))]
     public SampleType Type { get; set; }
 }

 public enum SampleType
 {
     AAAA,
     BBBB,
     CCCC
 }

如果有不够的地方,自行添加。

相关推荐
qq_410194293 小时前
.NET 性能优化:先找瓶颈,再谈技巧
性能优化·.net
玩泥巴的3 小时前
把AI编码从自由生成到受约束声明:微信生态 .NET SDK 中用源生成器压制 AI 编码幻觉的工程实践
微信·.net·aot·roslyn
Jeff-Tsai4 小时前
Day 10:多数据库支持:CRUD 与结构升级
.net·架构设计·erp·definition-driven
1-1=04 小时前
C# 特性(Attribute)
c#·.net·.netcore
IT规划师5 小时前
Redis 数据类型全解 - Bitmap 生产实战:把位视图讲准、用对、守住红线(六)
redis·.net
翊众建站16 小时前
用 JSON-LD 给企业官网做结构化数据:LocalBusiness 与 FAQPage 实践笔记
人工智能·搜索引擎·json
Patrick_Wilson1 天前
读懂一个 Go JSON 处理函数:从输入数据追踪结构体、校验与错误返回
go·json·编程语言
淡海水1 天前
10-01-互操作-C#与C++边界的内存管理
unity·c#·游戏引擎·.netcore·gc
WarPigs1 天前
C#把byte[]以十六进制打印,带分割符
c#
暴走约伯1 天前
【VFX工具链源码拆解 04】拯救丢失的绑定:Timeline 一键克隆与层级相对路径重映射算法
unity·c#·游戏引擎·硬件工程