using System.Collections;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Text.Json.Nodes;
public class NoIndentationConverter<T> : DefaultConverterFactory<T>
protected override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions modifiedOptions)
var bufferWriter = new ArrayBufferWriter<byte>();
Span<byte> buffer = stackalloc byte[4];
foreach (var rune in writer.GetCurrentUtf8Indent(includeNewline : true))
int length = rune.EncodeToUtf8(buffer);
bufferWriter.Write(buffer.Slice(0, length));
using (var innerWriter = new Utf8JsonWriter(bufferWriter))
JsonSerializer.Serialize(innerWriter, value, modifiedOptions);
writer.WriteRawValue(bufferWriter.WrittenSpan, skipInputValidation : true);
protected override JsonSerializerOptions ModifyOptions(JsonSerializerOptions options) { (options = base.ModifyOptions(options)).WriteIndented = false; return options; }
public abstract class DefaultConverterFactory<T> : JsonConverterFactory
class DefaultConverter : JsonConverter<T>
readonly JsonSerializerOptions modifiedOptions;
readonly DefaultConverterFactory<T> factory;
public DefaultConverter(JsonSerializerOptions modifiedOptions, DefaultConverterFactory<T> factory) => (this.modifiedOptions, this.factory) = (modifiedOptions, factory);
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) => factory.Write(writer, value, modifiedOptions);
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => factory.Read(ref reader, typeToConvert, modifiedOptions);
public override bool CanConvert(Type typeToConvert) => typeof(T).IsAssignableFrom(typeToConvert);
protected virtual JsonSerializerOptions ModifyOptions(JsonSerializerOptions options)
=> options.CopyAndRemoveConverter(this.GetType());
protected virtual T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions modifiedOptions)
=> (T?)JsonSerializer.Deserialize(ref reader, typeToConvert, modifiedOptions);
protected virtual void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions modifiedOptions)
=> JsonSerializer.Serialize(writer, value, modifiedOptions);
public override bool CanConvert(Type typeToConvert) => typeof(T) == typeToConvert;
public sealed override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => new DefaultConverter(ModifyOptions(options), this);
public static class JsonSerializerExtensions
public static IEnumerable<Rune> GetCurrentUtf8Indent(this Utf8JsonWriter writer, bool includeNewline = true)
if (!writer.Options.Indented || writer.CurrentDepth == 0)
return Array.Empty<Rune>();
var indentCharacter = ' ';
var runes = Enumerable.Range(0, indentSize * writer.CurrentDepth).Select(i => new Rune(indentCharacter));
runes = Environment.NewLine.EnumerateRunes().Concat(runes);
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);
public static void Test()
List<ExpandoObject> items = new List<ExpandoObject>();
for (int i = 0; i < itemCount; ++i)
dynamic item = new ExpandoObject();
item.prop2 = (char)('a' + i);
using (MemoryStream outputStream = new MemoryStream())
JsonSerializerOptions writeItemOptions = new JsonSerializerOptions()
{ new NoIndentationConverter<ExpandoObject>() },
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
JsonSerializer.Serialize(outputStream, items, writeItemOptions);
outputStream.Position = 0;
using (StreamReader sr = new StreamReader(outputStream, leaveOpen: true))
outputJson = sr.ReadToEnd();
Console.WriteLine(outputJson);
Assert.That(requiredJson == outputJson);
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: ");