Build / Build (push) Successful in 32s
PrivaPub's own types are read through the shared ClientModels context, and a type without generated metadata no longer falls back to reflection silently: it fails at once in development and on the pasture, and is reported on the console elsewhere. Startup outside production checks that every PrivaPub and Mastodon type the client knows has its metadata. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W4YtEJrgxG12Pc39Fai8Bd
49 lines
1.9 KiB
C#
49 lines
1.9 KiB
C#
using System.Collections.Concurrent;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using System.Text.Json.Serialization.Metadata;
|
|
|
|
using decePubClient.Models.Mastodon;
|
|
|
|
using PrivaPub.ClientModels;
|
|
|
|
namespace decePubClient.Helpers
|
|
{
|
|
public sealed class UnregisteredJson : IJsonTypeInfoResolver
|
|
{
|
|
public static readonly UnregisteredJson Instance = new();
|
|
static readonly DefaultJsonTypeInfoResolver Reflection = new();
|
|
static readonly ConcurrentDictionary<Type, byte> Reported = new();
|
|
|
|
public static bool Strict { get; set; }
|
|
|
|
public JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
|
|
{
|
|
if (Strict)
|
|
throw new NotSupportedException($"{type.FullName} is not registered in a JsonSerializerContext (HR0306).");
|
|
if (Reported.TryAdd(type, 0))
|
|
Console.Error.WriteLine($"{type.FullName} is serialized without a JsonSerializerContext registration (HR0306)");
|
|
return Reflection.GetTypeInfo(type, options);
|
|
}
|
|
|
|
public static void Check(bool strict)
|
|
{
|
|
Strict = strict;
|
|
if (!strict)
|
|
return;
|
|
var missing = Missing(ClientModelsJsonContext.Default, typeof(WebResult), "PrivaPub.ClientModels")
|
|
.Concat(Missing(MastodonJsonContext.Default, typeof(Status), "decePubClient.Models.Mastodon"))
|
|
.ToList();
|
|
if (missing.Count > 0)
|
|
throw new InvalidOperationException("Not registered in a JsonSerializerContext (HR0306): " + string.Join(", ", missing));
|
|
}
|
|
|
|
static IEnumerable<string> Missing(IJsonTypeInfoResolver context, Type anchor, string space) =>
|
|
anchor.Assembly.GetTypes()
|
|
.Where(t => t.IsClass && t.IsPublic && !t.IsAbstract && !t.IsGenericTypeDefinition && t.Namespace is { } ns && ns.StartsWith(space, StringComparison.Ordinal)
|
|
&& !ns.EndsWith(".Resources", StringComparison.Ordinal) && !typeof(Attribute).IsAssignableFrom(t) && !typeof(JsonSerializerContext).IsAssignableFrom(t))
|
|
.Where(t => context.GetTypeInfo(t, new JsonSerializerOptions()) == null)
|
|
.Select(t => t.FullName);
|
|
}
|
|
}
|