🐛 Fix JSON serialization caused issue
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Shared.Proto;
|
||||
using Google.Protobuf;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace DysonNetwork.Shared.Data;
|
||||
|
||||
@@ -42,14 +42,20 @@ public class CloudFileReferenceObject : ModelBase, ICloudFile
|
||||
{
|
||||
Id = proto.Id,
|
||||
Name = proto.Name,
|
||||
FileMeta = JsonConvert.DeserializeObject<Dictionary<string, object?>>(
|
||||
FileMeta = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
|
||||
proto.FileMeta.ToStringUtf8(),
|
||||
GrpcTypeHelper.SerializerSettings
|
||||
) ?? [],
|
||||
UserMeta = JsonConvert.DeserializeObject<Dictionary<string, object?>>(
|
||||
GrpcTypeHelper.SerializerOptions
|
||||
)?.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value.ValueKind == JsonValueKind.Undefined ? null : kvp.Value.Deserialize<object?>(GrpcTypeHelper.SerializerOptions)
|
||||
) ?? new Dictionary<string, object?>(),
|
||||
UserMeta = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
|
||||
proto.UserMeta.ToStringUtf8(),
|
||||
GrpcTypeHelper.SerializerSettings
|
||||
) ?? [],
|
||||
GrpcTypeHelper.SerializerOptions
|
||||
)?.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value.ValueKind == JsonValueKind.Undefined ? null : kvp.Value.Deserialize<object?>(GrpcTypeHelper.SerializerOptions)
|
||||
) ?? new Dictionary<string, object?>(),
|
||||
MimeType = proto.MimeType,
|
||||
Hash = proto.Hash,
|
||||
Size = proto.Size,
|
||||
@@ -76,12 +82,12 @@ public class CloudFileReferenceObject : ModelBase, ICloudFile
|
||||
|
||||
// Convert file metadata
|
||||
proto.FileMeta = ByteString.CopyFromUtf8(
|
||||
JsonConvert.SerializeObject(FileMeta, GrpcTypeHelper.SerializerSettings)
|
||||
JsonSerializer.Serialize(FileMeta, GrpcTypeHelper.SerializerOptions)
|
||||
);
|
||||
|
||||
// Convert user metadata
|
||||
proto.UserMeta = ByteString.CopyFromUtf8(
|
||||
JsonConvert.SerializeObject(UserMeta, GrpcTypeHelper.SerializerSettings)
|
||||
JsonSerializer.Serialize(UserMeta, GrpcTypeHelper.SerializerOptions)
|
||||
);
|
||||
|
||||
return proto;
|
||||
|
152
DysonNetwork.Shared/Data/JsonExtensions.cs
Normal file
152
DysonNetwork.Shared/Data/JsonExtensions.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
|
||||
namespace DysonNetwork.Shared.Data;
|
||||
|
||||
public static class JsonExtensions
|
||||
{
|
||||
public static Action<JsonTypeInfo> UnignoreAllProperties() =>
|
||||
typeInfo =>
|
||||
{
|
||||
if (typeInfo.Kind == JsonTypeInfoKind.Object)
|
||||
// [JsonIgnore] is implemented by setting ShouldSerialize to a function that returns false.
|
||||
foreach (var property in typeInfo.Properties.Where(ShouldUnignore))
|
||||
{
|
||||
property.Get ??= CreatePropertyGetter(property);
|
||||
property.Set ??= CreatePropertySetter(property);
|
||||
if (property.Get != null)
|
||||
property.ShouldSerialize = null;
|
||||
}
|
||||
};
|
||||
|
||||
public static Action<JsonTypeInfo> UnignoreAllProperties(Type type) =>
|
||||
typeInfo =>
|
||||
{
|
||||
if (type.IsAssignableFrom(typeInfo.Type) && typeInfo.Kind == JsonTypeInfoKind.Object)
|
||||
// [JsonIgnore] is implemented by setting ShouldSerialize to a function that returns false.
|
||||
foreach (var property in typeInfo.Properties.Where(ShouldUnignore))
|
||||
{
|
||||
property.Get ??= CreatePropertyGetter(property);
|
||||
property.Set ??= CreatePropertySetter(property);
|
||||
if (property.Get != null)
|
||||
property.ShouldSerialize = null;
|
||||
}
|
||||
};
|
||||
|
||||
public static Action<JsonTypeInfo> UnignoreProperties(Type type, params string[] properties) =>
|
||||
typeInfo =>
|
||||
{
|
||||
if (type.IsAssignableFrom(typeInfo.Type) && typeInfo.Kind == JsonTypeInfoKind.Object)
|
||||
// [JsonIgnore] is implemented by setting ShouldSerialize to a function that returns false.
|
||||
foreach (var property in typeInfo.Properties.Where(p => ShouldUnignore(p, properties)))
|
||||
{
|
||||
property.Get ??= CreatePropertyGetter(property);
|
||||
property.Set ??= CreatePropertySetter(property);
|
||||
if (property.Get != null)
|
||||
property.ShouldSerialize = null;
|
||||
}
|
||||
};
|
||||
|
||||
public static Action<JsonTypeInfo> UnignorePropertiesForDeserialize(Type type, params string[] properties) =>
|
||||
typeInfo =>
|
||||
{
|
||||
if (type.IsAssignableFrom(typeInfo.Type) && typeInfo.Kind == JsonTypeInfoKind.Object)
|
||||
// [JsonIgnore] is implemented by setting ShouldSerialize to a function that returns false.
|
||||
foreach (var property in typeInfo.Properties.Where(p => ShouldUnignore(p, properties)))
|
||||
{
|
||||
property.Set ??= CreatePropertySetter(property);
|
||||
}
|
||||
};
|
||||
|
||||
static bool ShouldUnignore(JsonPropertyInfo property) =>
|
||||
property.ShouldSerialize != null &&
|
||||
property.AttributeProvider?.IsDefined(typeof(JsonIgnoreAttribute), true) == true;
|
||||
|
||||
static bool ShouldUnignore(JsonPropertyInfo property, string[] properties) =>
|
||||
property.ShouldSerialize != null &&
|
||||
property.AttributeProvider?.IsDefined(typeof(JsonIgnoreAttribute), true) == true &&
|
||||
properties.Contains(property.GetMemberName());
|
||||
|
||||
// CreateGetter() and CreateSetter() taken from this answer https://stackoverflow.com/a/76296944/3744182
|
||||
// To https://stackoverflow.com/questions/61869393/get-net-core-jsonserializer-to-serialize-private-members
|
||||
|
||||
delegate TValue RefFunc<TObject, TValue>(ref TObject arg);
|
||||
|
||||
static Func<object, object?>? CreatePropertyGetter(JsonPropertyInfo property) =>
|
||||
property.GetPropertyInfo() is { } info && info.ReflectedType != null && info.GetGetMethod() is { } getMethod
|
||||
? CreateGetter(info.ReflectedType, getMethod)
|
||||
: null;
|
||||
|
||||
static Func<object, object?>? CreateGetter(Type type, MethodInfo? method)
|
||||
{
|
||||
if (method == null)
|
||||
return null;
|
||||
var myMethod = typeof(JsonExtensions).GetMethod(nameof(JsonExtensions.CreateGetterGeneric),
|
||||
BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||
return (Func<object, object?>)(myMethod.MakeGenericMethod(new[] { type, method.ReturnType })
|
||||
.Invoke(null, new[] { method })!);
|
||||
}
|
||||
|
||||
static Func<object, object?> CreateGetterGeneric<TObject, TValue>(MethodInfo method)
|
||||
{
|
||||
if (method == null)
|
||||
throw new ArgumentNullException();
|
||||
if (typeof(TObject).IsValueType)
|
||||
{
|
||||
// https://stackoverflow.com/questions/4326736/how-can-i-create-an-open-delegate-from-a-structs-instance-method
|
||||
// https://stackoverflow.com/questions/1212346/uncurrying-an-instance-method-in-net/1212396#1212396
|
||||
var func = (RefFunc<TObject, TValue>)Delegate.CreateDelegate(typeof(RefFunc<TObject, TValue>), null,
|
||||
method);
|
||||
return (o) =>
|
||||
{
|
||||
var tObj = (TObject)o;
|
||||
return func(ref tObj);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var func = (Func<TObject, TValue>)Delegate.CreateDelegate(typeof(Func<TObject, TValue>), method);
|
||||
return (o) => func((TObject)o);
|
||||
}
|
||||
}
|
||||
|
||||
static Action<object, object?>? CreatePropertySetter(JsonPropertyInfo property) =>
|
||||
property.GetPropertyInfo() is { } info && info.ReflectedType != null && info.GetSetMethod() is { } setMethod
|
||||
? CreateSetter(info.ReflectedType, setMethod)
|
||||
: null;
|
||||
|
||||
static Action<object, object?>? CreateSetter(Type type, MethodInfo? method)
|
||||
{
|
||||
if (method == null)
|
||||
return null;
|
||||
var myMethod = typeof(JsonExtensions).GetMethod(nameof(JsonExtensions.CreateSetterGeneric),
|
||||
BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||
return (Action<object, object?>)(myMethod
|
||||
.MakeGenericMethod(new[] { type, method.GetParameters().Single().ParameterType })
|
||||
.Invoke(null, new[] { method })!);
|
||||
}
|
||||
|
||||
static Action<object, object?>? CreateSetterGeneric<TObject, TValue>(MethodInfo method)
|
||||
{
|
||||
if (method == null)
|
||||
throw new ArgumentNullException();
|
||||
if (typeof(TObject).IsValueType)
|
||||
{
|
||||
// TODO: find a performant way to do this. Possibilities:
|
||||
// Box<T> from Microsoft.Toolkit.HighPerformance
|
||||
// https://stackoverflow.com/questions/18937935/how-to-mutate-a-boxed-struct-using-il
|
||||
return (o, v) => method.Invoke(o, new[] { v });
|
||||
}
|
||||
else
|
||||
{
|
||||
var func = (Action<TObject, TValue?>)Delegate.CreateDelegate(typeof(Action<TObject, TValue?>), method);
|
||||
return (o, v) => func((TObject)o, (TValue?)v);
|
||||
}
|
||||
}
|
||||
|
||||
static PropertyInfo? GetPropertyInfo(this JsonPropertyInfo property) =>
|
||||
(property.AttributeProvider as PropertyInfo);
|
||||
|
||||
static string? GetMemberName(this JsonPropertyInfo property) => (property.AttributeProvider as MemberInfo)?.Name;
|
||||
}
|
Reference in New Issue
Block a user