Replacing Newtonsoft.Json with System.Text.Json (experimental)

This commit is contained in:
Florian Zevedei 2024-09-25 16:56:03 +02:00
parent f21dec5f1c
commit 0e8e96f2d8
8 changed files with 248 additions and 25 deletions

View File

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
@ -126,7 +126,7 @@ public class MessageResult : ResultBase
T cd = null;
try
{
cd = JsonConvert.DeserializeObject<T>(RawData);
cd = JsonSerializer.Deserialize<T>(RawData);
return cd;
}

View File

@ -1,4 +1,5 @@
using TelegramBotBase.Interfaces;
using System;
using TelegramBotBase.Interfaces;
namespace TelegramBotBase.Builder.Interfaces;
@ -39,6 +40,7 @@ public interface ISessionSerializationStage
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
[Obsolete("Use UseJSON instead.")]
ILanguageSelectionStage UseSimpleJSON();
/// <summary>
@ -46,6 +48,7 @@ public interface ISessionSerializationStage
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
[Obsolete("Use UseJSON instead.")]
ILanguageSelectionStage UseSimpleJSON(string path);
/// <summary>

View File

@ -1,16 +1,18 @@
using Newtonsoft.Json;
using System.Text.Json;
using System.Text;
using TelegramBotBase.Exceptions;
using System.Text.Json.Serialization;
namespace TelegramBotBase.Form;
/// <summary>
/// Base class for serializing buttons and data
/// Base class for serializing buttons and data
/// </summary>
public class CallbackData
{
public CallbackData()
{
}
public CallbackData(string method, string value)
@ -19,9 +21,9 @@ public class CallbackData
Value = value;
}
[JsonProperty("m")] public string Method { get; set; }
[JsonPropertyName("m")] public string Method { get; set; }
[JsonProperty("v")] public string Value { get; set; }
[JsonPropertyName("v")] public string Value { get; set; }
public static string Create(string method, string value)
{
@ -36,7 +38,7 @@ public class CallbackData
{
var s = string.Empty;
s = JsonConvert.SerializeObject(this);
s = JsonSerializer.Serialize(this);
//Is data over 64 bytes ?
int byte_count = Encoding.UTF8.GetByteCount(s);
@ -55,7 +57,7 @@ public class CallbackData
/// <returns></returns>
public static CallbackData Deserialize(string data)
{
return JsonConvert.DeserializeObject<CallbackData>(data);
return JsonSerializer.Deserialize<CallbackData>(data);
}
public static implicit operator string(CallbackData callbackData) => callbackData.Serialize(true);

View File

@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace TelegramBotBase.States.Converter
{
public class DictionaryObjectJsonConverter : JsonConverter<Dictionary<string, object>>
{
public override Dictionary<string, object> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var dictionary = new Dictionary<string, object>();
var jsonDocument = JsonDocument.ParseValue(ref reader);
foreach (var element in jsonDocument.RootElement.EnumerateObject())
{
switch (element.Value.ValueKind)
{
case JsonValueKind.String:
dictionary[element.Name] = element.Value.GetString();
break;
case JsonValueKind.Number:
if (element.Value.TryGetInt32(out var number))
{
dictionary[element.Name] = number;
continue;
}
if (element.Value.TryGetInt64(out long l))
dictionary[element.Name] = l;
else
dictionary[element.Name] = element.Value.GetDouble();
break;
case JsonValueKind.True:
case JsonValueKind.False:
dictionary[element.Name] = element.Value.GetBoolean();
break;
case JsonValueKind.Object:
dictionary[element.Name] = JsonSerializer.Deserialize<Dictionary<string, object>>(element.Value.GetRawText(), options);
break;
case JsonValueKind.Array:
dictionary[element.Name] = HandleArray(element.Value);
break;
default:
dictionary[element.Name] = element.Value.GetRawText();
break;
}
}
return dictionary;
}
private object HandleArray(JsonElement jsonArray)
{
// Hier wird geprüft, ob alle Elemente einer bestimmten Art angehören (z. B. int, string)
if (jsonArray.GetArrayLength() > 0)
{
var firstElement = jsonArray[0];
switch (firstElement.ValueKind)
{
case JsonValueKind.Number:
// Prüfen, ob alle Elemente ganze Zahlen sind
var isIntArray = true;
var isLongArray = false;
foreach (var element in jsonArray.EnumerateArray())
{
if (!element.TryGetInt32(out _))
{
isIntArray = false;
isLongArray = true;
if (!element.TryGetInt64(out _))
{
isLongArray = false;
break;
}
}
}
if (isIntArray)
{
var list = new List<int>();
foreach (var element in jsonArray.EnumerateArray())
{
list.Add(element.GetInt32());
}
return list;
}
else if (isLongArray)
{
var list = new List<long>();
foreach (var element in jsonArray.EnumerateArray())
{
list.Add(element.GetInt64());
}
return list;
}
else
{
var list = new List<double>();
foreach (var element in jsonArray.EnumerateArray())
{
list.Add(element.GetDouble());
}
return list;
}
case JsonValueKind.String:
var stringList = new List<string>();
foreach (var element in jsonArray.EnumerateArray())
{
stringList.Add(element.GetString());
}
return stringList;
case JsonValueKind.True:
case JsonValueKind.False:
var boolList = new List<bool>();
foreach (var element in jsonArray.EnumerateArray())
{
boolList.Add(element.GetBoolean());
}
return boolList;
default:
// Fallback: Liste von Objekten (z. B. wenn es sich um komplexe Objekte handelt)
var objectList = new List<object>();
foreach (var element in jsonArray.EnumerateArray())
{
objectList.Add(JsonSerializer.Deserialize<object>(element.GetRawText()));
}
return objectList;
}
}
// Leeres Array als Liste von Objekten zurückgeben
return new List<object>();
}
public override void Write(Utf8JsonWriter writer, Dictionary<string, object> value, JsonSerializerOptions options)
{
writer.WriteStartObject();
foreach (var kvp in value)
{
writer.WritePropertyName(kvp.Key);
JsonSerializer.Serialize(writer, kvp.Value, kvp.Value?.GetType() ?? typeof(object), options);
}
writer.WriteEndObject();
}
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace TelegramBotBase.States.Converter
{
public class JsonTypeConverter : JsonConverter<object>
{
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var jsonDocument = JsonDocument.ParseValue(ref reader);
var type = Type.GetType(jsonDocument.RootElement.GetProperty("$type").GetString());
var jsonObject = jsonDocument.RootElement.GetRawText();
return JsonSerializer.Deserialize(jsonObject, type, options);
}
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteString("$type", value.GetType().AssemblyQualifiedName);
var json = JsonSerializer.Serialize(value, value.GetType(), options);
using var jsonDoc = JsonDocument.Parse(json);
foreach (var property in jsonDoc.RootElement.EnumerateObject())
{
property.WriteTo(writer);
}
writer.WriteEndObject();
}
}
}

View File

@ -1,6 +1,6 @@
using System;
using System.IO;
using Newtonsoft.Json;
using System.Text.Json;
using TelegramBotBase.Args;
using TelegramBotBase.Base;
using TelegramBotBase.Form;
@ -48,11 +48,15 @@ public class JsonStateMachine : IStateMachine
{
var content = File.ReadAllText(FilePath);
var sc = JsonConvert.DeserializeObject<StateContainer>(content, new JsonSerializerSettings
var options = new JsonSerializerOptions
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
});
Converters = {
new Converter.DictionaryObjectJsonConverter(),
new Converter.JsonTypeConverter()
}
};
var sc = JsonSerializer.Deserialize<StateContainer>(content, options);
return sc;
}
@ -77,11 +81,16 @@ public class JsonStateMachine : IStateMachine
try
{
var content = JsonConvert.SerializeObject(e.States, Formatting.Indented, new JsonSerializerSettings
var options = new JsonSerializerOptions
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
});
WriteIndented = true,
Converters = {
new Converter.DictionaryObjectJsonConverter(),
new Converter.JsonTypeConverter()
}
};
var content = JsonSerializer.Serialize(e.States, options);
File.WriteAllText(FilePath, content);
}

View File

@ -1,6 +1,6 @@
using System;
using System.IO;
using Newtonsoft.Json;
using System.Text.Json;
using TelegramBotBase.Args;
using TelegramBotBase.Base;
using TelegramBotBase.Form;
@ -49,7 +49,15 @@ public class SimpleJsonStateMachine : IStateMachine
{
var content = File.ReadAllText(FilePath);
var sc = JsonConvert.DeserializeObject<StateContainer>(content);
var options = new JsonSerializerOptions
{
Converters = {
new Converter.DictionaryObjectJsonConverter(),
new Converter.JsonTypeConverter()
}
};
var sc = JsonSerializer.Deserialize<StateContainer>(content, options);
return sc;
}
@ -74,7 +82,16 @@ public class SimpleJsonStateMachine : IStateMachine
try
{
var content = JsonConvert.SerializeObject(e.States, Formatting.Indented);
var options = new JsonSerializerOptions
{
WriteIndented = true,
Converters = {
new Converter.DictionaryObjectJsonConverter(),
new Converter.JsonTypeConverter()
}
};
var content = JsonSerializer.Serialize(e.States, options);
File.WriteAllText(FilePath, content);
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.1;net6;net7;net8</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1;net6;net7;net8</TargetFrameworks>
<LangVersion>10</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
@ -22,8 +22,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
</ItemGroup>
@ -62,7 +62,7 @@
<ItemGroup>
<ProjectReference Include="..\TelegramBotBase.SourceGenerators\TelegramBotBase.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" TargetFramework="netstandard2.0" />
<ProjectReference Include="..\TelegramBotBase.SourceGenerators\TelegramBotBase.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" TargetFramework="netstandard2.0" />
</ItemGroup>
</Project>