Experimental: try using JsonPolymorphic rather than custom JsonConvert logic

This commit is contained in:
Rory&
2026-09-08 01:25:34 +02:00
parent 81292a4711
commit cca30e7027
2 changed files with 4 additions and 142 deletions
@@ -1,6 +1,5 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
@@ -9,7 +8,9 @@ namespace Spacebar.Models.Generic;
[DebuggerDisplay("{User.Id} ({User.Username}#{User.Discriminator})")]
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
[SuppressMessage("ReSharper", "PropertyCanBeMadeInitOnly.Global")]
[JsonConverter(typeof(MemberJsonConverter))]
[JsonPolymorphic]
[JsonDerivedType(typeof(Member))]
[JsonDerivedType(typeof(MemberWithPresence))]
public class Member
{
[JsonPropertyName("user")]
@@ -45,143 +46,4 @@ public class MemberWithPresence : Member
{
[JsonPropertyName("presence")]
public Presence? Presence { get; set; }
}
public class MemberJsonConverter : JsonConverter<Member>
{
public override Member? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
return null;
using var document = JsonDocument.ParseValue(ref reader);
var jsonObject = document.RootElement;
if (jsonObject.ValueKind != JsonValueKind.Object)
throw new JsonException("Expected member payload to be a JSON object.");
var hasPresence = jsonObject.TryGetProperty("presence", out _);
Member member = hasPresence
? new MemberWithPresence { User = null! }
: new Member { User = null! };
var hasUser = false;
foreach (var property in jsonObject.EnumerateObject())
{
switch (property.Name)
{
case "user":
member.User = property.Value.Deserialize<PartialUser>(options) ?? throw new JsonException("The required member user field is invalid.");
hasUser = true;
break;
case "nick":
member.Nick = property.Value.ValueKind == JsonValueKind.Null ? null : property.Value.GetString();
break;
case "avatar":
member.Avatar = property.Value.ValueKind == JsonValueKind.Null ? null : property.Value.GetString();
break;
case "avatar_decoration_data":
member.AvatarDecorationData = property.Value.ValueKind == JsonValueKind.Null ? null : JsonNode.Parse(property.Value.GetRawText()) as JsonObject;
break;
case "collectibles":
member.Collectibles = property.Value.ValueKind == JsonValueKind.Null ? null : JsonNode.Parse(property.Value.GetRawText()) as JsonObject;
break;
case "display_name_styles":
if (property.Value.ValueKind != JsonValueKind.Null)
member.DisplayNameStyles = property.Value.Deserialize<DisplayNameStyle>(options);
break;
case "banner":
member.Banner = property.Value.ValueKind == JsonValueKind.Null ? null : property.Value.GetString();
break;
case "bio":
member.Bio = property.Value.ValueKind == JsonValueKind.Null ? null : property.Value.GetString();
break;
case "roles":
if (property.Value.ValueKind == JsonValueKind.Null)
{
member.Roles = null;
break;
}
if (property.Value.ValueKind != JsonValueKind.Array)
throw new JsonException("Expected roles to be an array.");
member.Roles = new List<long>();
foreach (var role in property.Value.EnumerateArray())
{
switch (role.ValueKind)
{
case JsonValueKind.Number:
member.Roles.Add(role.GetInt64());
break;
case JsonValueKind.String:
if (!long.TryParse(role.GetString(), out var roleId))
throw new JsonException("Invalid role id.");
member.Roles.Add(roleId);
break;
default:
throw new JsonException("Invalid role id value kind.");
}
}
break;
case "presence":
if (member is MemberWithPresence memberWithPresence && property.Value.ValueKind != JsonValueKind.Null)
memberWithPresence.Presence = property.Value.Deserialize<Presence>(options);
break;
}
}
if (!hasUser)
throw new JsonException("The required member user field is missing.");
return member;
}
public override void Write(Utf8JsonWriter writer, Member value, JsonSerializerOptions options)
{
writer.WriteStartObject();
{
writer.WritePropertyName("user");
JsonSerializer.Serialize(writer, value.User);
if (value.Nick != null) writer.WriteString("nick", value.Nick);
if (value.Avatar != null) writer.WriteString("avatar", value.Avatar);
if (value.AvatarDecorationData != null)
{
writer.WritePropertyName("avatar_decoration_data");
JsonSerializer.Serialize(writer, value.AvatarDecorationData);
}
if (value.Collectibles != null)
{
writer.WritePropertyName("collectibles");
JsonSerializer.Serialize(writer, value.Collectibles);
}
writer.WritePropertyName("display_name_styles");
if (value.DisplayNameStyles != null)
{
JsonSerializer.Serialize(writer, value.DisplayNameStyles);
}
else writer.WriteNullValue();
if (value.Banner != null) writer.WriteString("banner", value.Banner);
if (value.Bio != null) writer.WriteString("bio", value.Bio);
if (value.Roles != null)
{
writer.WritePropertyName("roles");
JsonSerializer.Serialize(writer, value.Roles);
}
if (value is MemberWithPresence mwp && mwp.Presence != null)
{
writer.WritePropertyName("presence");
JsonSerializer.Serialize(writer, mwp.Presence);
}
}
writer.WriteEndObject();
}
}
@@ -29,7 +29,7 @@ public class Op14Controller(ILogger<Op12Controller> logger, SpacebarAspNetAuthen
public async IAsyncEnumerable<ContentlessReplicationMessage> DoLazyRequest([FromBody] LazyRequest payload)
{
var user = await TraceResult.TraceAsync("getAuthUser", () => authService.GetCurrentUserAsync(Request));
var session = await TraceResult.TraceAsync("getAuthSession", () => authService.GetCurrentSessionAsync(Request));
// var session = await TraceResult.TraceAsync("getAuthSession", () => authService.GetCurrentSessionAsync(Request));
if (!await db.Members.AsNoTracking().AnyAsync(m => m.GuildId == payload.GuildId && m.Id == user.Result.Id))
{