Last active
March 9, 2025 12:33
-
-
Save davepermen/5d2ac12ccaa53f9ca1d298e477735eb4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using HomeTests; | |
using JsonTests; | |
using System.Text.Json; | |
using WebDeviceTests; | |
var options = JsonSerializerOptions.Web.WithPolymorphicTypesFor<Event>(configure => | |
{ | |
configure | |
.IncludeTypesFromNamespaceWith<WebButtonEvent>() | |
.IncludeType<HomeStateEvent>() | |
; | |
}); | |
Event[] events = [ | |
new WebButtonEvent("123"), | |
new WebImageEvent("https://inklay.conesoft.net/cooper.jpg"), | |
new HomeStateEvent("home/kitchen", "on") | |
]; | |
var serialized = JsonSerializer.Serialize(events, options); | |
Console.WriteLine(serialized); | |
Console.WriteLine(); | |
var _events = JsonSerializer.Deserialize<Event[]>(serialized, options) ?? []; | |
foreach (var _event in _events) | |
{ | |
Console.WriteLine(_event switch | |
{ | |
WebButtonEvent button => $"webbuttonevent: {button.Id}", | |
HomeStateEvent home => $"homestateevent: {home.Path} = {home.Value}", | |
WebImageEvent image => $"webimageevent: {image.Url}", | |
_ => "error" | |
}); | |
} | |
/* demo types */ | |
record Event; | |
namespace WebDeviceTests | |
{ | |
record WebButtonEvent(string Id) : Event; | |
record WebImageEvent(string Url) : Event; | |
} | |
namespace HomeTests | |
{ | |
record HomeStateEvent(string Path, string Value) : Event; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace JsonTests; | |
public class TypeCollector<Base>(List<Type> types) | |
{ | |
public TypeCollector<Base> IncludeType<T>() where T : Base | |
{ | |
types.Add(typeof(T)); | |
return this; | |
} | |
public TypeCollector<Base> IncludeTypesFromNamespaceWith<T>() | |
{ | |
types.AddRange(AppDomain.CurrentDomain | |
.GetAssemblies() | |
.SelectMany(a => a.GetTypes()) | |
.Where(t => t.IsSubclassOf(typeof(Base)) && t.Namespace == typeof(T).Namespace) | |
); | |
return this; | |
} | |
public static IEnumerable<Type> Collect<T>(Action<TypeCollector<T>>? configure) | |
{ | |
List<Type> types = []; | |
configure?.Invoke(new TypeCollector<T>(types)); | |
if (configure == null) | |
{ | |
types.AddRange(AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.IsSubclassOf(typeof(T)))); | |
} | |
return types; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Text.Json; | |
using System.Text.Json.Serialization; | |
using System.Text.Json.Serialization.Metadata; | |
namespace JsonTests; | |
public static class WithPolymorphicTypesExtensions | |
{ | |
public static JsonSerializerOptions WithPolymorphicTypesFor<T>(this JsonSerializerOptions jsonSerializerOptions, Action<TypeCollector<T>>? configure = null, string? propertyName = null) => new(jsonSerializerOptions) | |
{ | |
TypeInfoResolver = new DefaultJsonTypeInfoResolver().WithAddedModifier(jsonTypeInfo => | |
{ | |
if (jsonTypeInfo.Type == typeof(T)) | |
{ | |
jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions | |
{ | |
TypeDiscriminatorPropertyName = propertyName ?? "type", | |
IgnoreUnrecognizedTypeDiscriminators = true, | |
UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization, | |
}; | |
foreach (var t in TypeCollector<T>.Collect(configure).Select(t => new JsonDerivedType(t, t.Name.ToLowerInvariant()))) | |
{ | |
jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add(t); | |
} | |
} | |
}) | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment