<PublishAot>true</PublishAot>
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
using System.Collections;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
public sealed class JsonCommentAttribute : JsonConverterAttribute
public JsonCommentAttribute(string Comment) { this.Comment = Comment; }
public override JsonConverter CreateConverter (Type typeToConvert) { return new JsonCommentConverter(Comment); }
public class JsonCommentConverter : JsonCommentConverter<object>
public JsonCommentConverter(string comment) : base(comment){ }
public class JsonCommentConverter<TBase> : DefaultConverterFactory<TBase>
readonly string CommentWithDelimiters;
public JsonCommentConverter(string comment)
this.CommentWithDelimiters = " /*" + comment + "*/";
protected override void Write<T>(Utf8JsonWriter writer, T value, JsonSerializerOptions modifiedOptions)
var json = JsonSerializer.Serialize(value, modifiedOptions);
writer.WriteRawValue(json + CommentWithDelimiters, skipInputValidation : true);
protected override JsonSerializerOptions ModifyOptions(JsonSerializerOptions options)
var modifiedOptions = base.ModifyOptions(options);
modifiedOptions.WriteIndented = false;
public abstract class DefaultConverterFactory<TBase> : JsonConverterFactory
class DefaultConverter<TConcrete> : JsonConverter<TConcrete> where TConcrete : TBase
readonly JsonSerializerOptions modifiedOptions;
readonly DefaultConverterFactory<TBase> factory;
public DefaultConverter(JsonSerializerOptions modifiedOptions, DefaultConverterFactory<TBase> factory) { this.modifiedOptions = modifiedOptions; this.factory = factory; }
public override void Write(Utf8JsonWriter writer, TConcrete value, JsonSerializerOptions options) { factory.Write(writer, value, modifiedOptions); }
public override TConcrete Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return factory.Read<TConcrete>(ref reader, typeToConvert, modifiedOptions); }
protected virtual JsonSerializerOptions ModifyOptions(JsonSerializerOptions options) { return options.CopyAndRemoveConverter(this.GetType()); }
protected virtual TConcrete Read<TConcrete>(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions modifiedOptions) where TConcrete : TBase
return (TConcrete)JsonSerializer.Deserialize(ref reader, typeToConvert, modifiedOptions);
protected virtual void Write<TConcrete>(Utf8JsonWriter writer, TConcrete value, JsonSerializerOptions modifiedOptions) where TConcrete : TBase
JsonSerializer.Serialize(writer, value, modifiedOptions);
public sealed override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
var modifiedOptions = ModifyOptions(options);
if (typeToConvert == typeof(TBase))
return new DefaultConverter<TBase>(modifiedOptions, this);
return (JsonConverter)Activator.CreateInstance(typeof(DefaultConverter<>).MakeGenericType(typeof(TBase), typeToConvert), new object [] {modifiedOptions, this });
public override bool CanConvert(Type typeToConvert) { return typeof(TBase).IsAssignableFrom(typeToConvert); }
public static partial class JsonExtensions
public static JsonSerializerOptions CopyAndRemoveConverter(this JsonSerializerOptions options, Type converterType)
var copy = new JsonSerializerOptions(options);
for (var i = copy.Converters.Count - 1; i >= 0; i--)
if (copy.Converters[i].GetType() == converterType)
copy.Converters.RemoveAt(i);
[JsonComment("Name of the person")]
public string Name { get; set; }
[JsonComment("Age of the person")]
public int Age { get; set; }
[JsonSerializable(typeof(Person))]
public partial class MySerializationContext : JsonSerializerContext;
public static void Test()
static void TestReflection()
var person = new Person { Name = "Jack", Age = 22 };
var options = new JsonSerializerOptions
ReadCommentHandling = JsonCommentHandling.Skip,
var json = JsonSerializer.Serialize(person, options);
var person2 = JsonSerializer.Deserialize<Person>(json, options);
Assert.That(person.Age == person2?.Age);
Assert.That(person.Name == person2?.Name);
static void TestSourceGen()
var person = new Person { Name = "Jack", Age = 22 };
var options = new JsonSerializerOptions
ReadCommentHandling = JsonCommentHandling.Skip,
var json = JsonSerializer.Serialize(person, options);
var person2 = JsonSerializer.Deserialize<Person>(json, options);
Assert.That(person.Age == person2?.Age);
Assert.That(person.Name == person2?.Name);
public static void Main()
Console.WriteLine("Environment version: {0} ({1}), {2}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Console.WriteLine("System.Text.Json version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");