Updating json serializer to fit System.Text.Json
This commit is contained in:
parent
19d8a23b98
commit
667ca5ba6c
@ -1,5 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
@ -11,27 +14,283 @@ namespace TelegramBotBase.States.Converter
|
|||||||
|
|
||||||
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
var jsonDocument = JsonDocument.ParseValue(ref reader);
|
using (JsonDocument doc = JsonDocument.ParseValue(ref reader))
|
||||||
var type = Type.GetType(jsonDocument.RootElement.GetProperty("$type").GetString());
|
{
|
||||||
var jsonObject = jsonDocument.RootElement.GetRawText();
|
return ParseElement(doc.RootElement, options, typeof(object));
|
||||||
return JsonSerializer.Deserialize(jsonObject, type, options);
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ParseElement(JsonElement element, JsonSerializerOptions options, Type expected_type)
|
||||||
|
{
|
||||||
|
// Wenn das Element ein JSON-Objekt ist
|
||||||
|
if (element.ValueKind == JsonValueKind.Object)
|
||||||
|
{
|
||||||
|
// Wenn es einen $type enthält, dann den Typ dynamisch instanziieren
|
||||||
|
if (element.TryGetProperty("$type", out JsonElement typeElement))
|
||||||
|
{
|
||||||
|
string typeName = typeElement.GetString();
|
||||||
|
Type type = Type.GetType(typeName);
|
||||||
|
|
||||||
|
if (type == null)
|
||||||
|
throw new InvalidOperationException($"Typ '{typeName}' konnte nicht gefunden werden.");
|
||||||
|
|
||||||
|
// Liste verarbeiten, falls $values enthalten ist
|
||||||
|
if (element.TryGetProperty("$values", out JsonElement valuesElement))
|
||||||
|
{
|
||||||
|
return ParseArray(valuesElement, type);
|
||||||
|
}
|
||||||
|
else if (expected_type.IsGenericType && expected_type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||||
|
{
|
||||||
|
var dictionary = new Dictionary<string, object>();
|
||||||
|
foreach (var property in element.EnumerateObject())
|
||||||
|
{
|
||||||
|
dictionary[property.Name] = ParseElement(property.Value, options, typeof(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dictionary;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var instance = type.GetConstructor(new Type[] { }).Invoke(new object[] { });
|
||||||
|
var properties = type.GetProperties();
|
||||||
|
|
||||||
|
foreach (var p in properties)
|
||||||
|
{
|
||||||
|
if (!element.TryGetProperty(p.Name, out JsonElement value))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (value.ValueKind)
|
||||||
|
{
|
||||||
|
case JsonValueKind.Number:
|
||||||
|
|
||||||
|
if (p.PropertyType == typeof(int))
|
||||||
|
{
|
||||||
|
if (value.TryGetInt32(out int i))
|
||||||
|
{
|
||||||
|
p.SetValue(instance, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p.PropertyType == typeof(long))
|
||||||
|
{
|
||||||
|
if (value.TryGetInt64(out long l))
|
||||||
|
{
|
||||||
|
p.SetValue(instance, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case JsonValueKind.String:
|
||||||
|
|
||||||
|
p.SetValue(instance, value.ToString());
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
//if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||||
|
//{
|
||||||
|
// var dictionary = new Dictionary<string, object>();
|
||||||
|
// foreach (var property in element.EnumerateObject())
|
||||||
|
// {
|
||||||
|
// dictionary[property.Name] = ParseElement(property.Value, options, p.PropertyType);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// p.SetValue(instance, dictionary);
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
|
||||||
|
var obj = ParseElement(value, options, p.PropertyType);
|
||||||
|
|
||||||
|
if (obj == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
p.SetValue(instance, obj);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
|
||||||
|
// Objekt dynamisch deserialisieren
|
||||||
|
//return JsonSerializer.Deserialize(element.GetRawText(), type, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Falls kein $type vorhanden ist, als Dictionary verarbeiten
|
||||||
|
var dictionary = new Dictionary<string, object>();
|
||||||
|
foreach (var property in element.EnumerateObject())
|
||||||
|
{
|
||||||
|
dictionary[property.Name] = ParseElement(property.Value, options, typeof(object));
|
||||||
|
}
|
||||||
|
return dictionary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Wenn das Element ein Array ist
|
||||||
|
else if (element.ValueKind == JsonValueKind.Array)
|
||||||
|
{
|
||||||
|
return ParseArray(element, typeof(object));
|
||||||
|
}
|
||||||
|
// Primitive Typen (String, Number, Bool)
|
||||||
|
else if (element.ValueKind == JsonValueKind.Number)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (expected_type == typeof(Int64))
|
||||||
|
{
|
||||||
|
if (element.TryGetInt64(out long l))
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
else if (expected_type == typeof(Int32))
|
||||||
|
{
|
||||||
|
if (element.TryGetInt32(out int i))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.TryGetInt32(out int i2))
|
||||||
|
return i2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (element.ValueKind == JsonValueKind.String)
|
||||||
|
{
|
||||||
|
return element.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
#if NETCOREAPP3_1
|
||||||
|
return JsonSerializer.Deserialize(element.ToString(), typeof(object), options);
|
||||||
|
#else
|
||||||
|
return element.Deserialize<object>(options);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ParseElement(JsonElement element)
|
||||||
|
{
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ParseArray(JsonElement arrayElement, Type listType)
|
||||||
|
{
|
||||||
|
// Wenn der Typ eine generische Liste ist
|
||||||
|
if (listType.IsGenericType && listType.GetGenericTypeDefinition() == typeof(List<>))
|
||||||
|
{
|
||||||
|
Type elementType = listType.GetGenericArguments()[0];
|
||||||
|
var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType));
|
||||||
|
foreach (var item in arrayElement.EnumerateArray())
|
||||||
|
{
|
||||||
|
list.Add(ParseElement(item, new JsonSerializerOptions(), elementType));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Standardmäßig als List<object>
|
||||||
|
var list = new List<object>();
|
||||||
|
foreach (var item in arrayElement.EnumerateArray())
|
||||||
|
{
|
||||||
|
list.Add(ParseElement(item, new JsonSerializerOptions(), typeof(object)));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
|
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
writer.WriteStartObject();
|
WriteWithTypeInfo(writer, value, options);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void WriteWithTypeInfo(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
writer.WriteNullValue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type = value.GetType();
|
||||||
|
|
||||||
|
// Primitives und grundlegende Typen (int, string, bool, etc.)
|
||||||
|
if (type.IsPrimitive || type == typeof(string) || type == typeof(decimal))
|
||||||
|
{
|
||||||
|
JsonSerializer.Serialize(writer, value, type, options);
|
||||||
|
}
|
||||||
|
// Behandlung für Sammlungen
|
||||||
|
else if (value is IList list)
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
writer.WriteString("$type", type.AssemblyQualifiedName);
|
||||||
|
writer.WritePropertyName("$values");
|
||||||
|
writer.WriteStartArray();
|
||||||
|
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
WriteWithTypeInfo(writer, item, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndArray();
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
// Behandlung für Dictionaries
|
||||||
|
else if (value is IDictionary dictionary)
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
writer.WriteString("$type", type.AssemblyQualifiedName);
|
||||||
|
|
||||||
|
foreach (DictionaryEntry entry in dictionary)
|
||||||
|
{
|
||||||
|
writer.WritePropertyName(entry.Key.ToString());
|
||||||
|
WriteWithTypeInfo(writer, entry.Value, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
// Komplexe Objekte
|
||||||
|
else if (value is Enum e)
|
||||||
|
{
|
||||||
|
|
||||||
|
int eValue = (int)value;
|
||||||
|
|
||||||
|
writer.WriteNumberValue(eValue);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
writer.WriteString("$type", type.AssemblyQualifiedName);
|
||||||
|
|
||||||
|
foreach (var property in type.GetProperties())
|
||||||
|
{
|
||||||
|
if (property.CanRead)
|
||||||
|
{
|
||||||
|
var propValue = property.GetValue(value);
|
||||||
|
writer.WritePropertyName(property.Name);
|
||||||
|
WriteWithTypeInfo(writer, propValue, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,18 +50,22 @@ public class JsonStateMachine : IStateMachine
|
|||||||
|
|
||||||
var options = new JsonSerializerOptions
|
var options = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
Converters = {
|
Converters = {
|
||||||
new Converter.DictionaryObjectJsonConverter(),
|
new Converter.JsonTypeConverter(),
|
||||||
new Converter.JsonTypeConverter()
|
//new Converter.DictionaryObjectJsonConverter(),
|
||||||
}
|
|
||||||
|
},
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
};
|
};
|
||||||
|
|
||||||
var sc = JsonSerializer.Deserialize<StateContainer>(content, options);
|
var obj = JsonSerializer.Deserialize<object>(content, options) ;
|
||||||
|
var sc = obj as StateContainer;
|
||||||
|
|
||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
catch
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new StateContainer();
|
return new StateContainer();
|
||||||
@ -85,17 +89,19 @@ public class JsonStateMachine : IStateMachine
|
|||||||
{
|
{
|
||||||
WriteIndented = true,
|
WriteIndented = true,
|
||||||
Converters = {
|
Converters = {
|
||||||
new Converter.DictionaryObjectJsonConverter(),
|
new Converter.JsonTypeConverter(),
|
||||||
new Converter.JsonTypeConverter()
|
},
|
||||||
}
|
PropertyNameCaseInsensitive = true
|
||||||
};
|
};
|
||||||
|
|
||||||
var content = JsonSerializer.Serialize(e.States, options);
|
var content = JsonSerializer.Serialize<object>(e.States, options);
|
||||||
|
|
||||||
File.WriteAllText(FilePath, content);
|
File.WriteAllText(FilePath, content);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user