using System.Collections;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Text.Json.Nodes;
string PascalCaseProperty { get; }
string SnakeCaseProperty { get; }
public class Model : IModel
public string PascalCaseProperty { get; set; } = "";
public string SnakeCaseProperty { get; set; } = "";
public record RecordModel(string PascalCaseProperty, string SnakeCaseProperty) : IModel { }
public static partial class JsonExtensions
public static Action<JsonTypeInfo> RemapNames(Type type, IEnumerable<KeyValuePair<string, string>> names)
var dictionary = names.ToDictionary(p => p.Key, p => p.Value).AsReadOnly();
if (typeInfo.Kind != JsonTypeInfoKind.Object || !type.IsAssignableFrom(typeInfo.Type))
foreach (var property in typeInfo.Properties)
if (property.GetMemberName() is {} memberName && dictionary.TryGetValue(memberName, out var jsonName))
property.Name = jsonName;
public static string? GetMemberName(this JsonPropertyInfo property) => (property.AttributeProvider as MemberInfo)?.Name;
public static void Test()
Test(new Model { PascalCaseProperty = "PascalCase Value", SnakeCaseProperty = "snake_case value" });
Test(new RecordModel("PascalCase Value", "snake_case value"));
static void Test<TModel>(TModel model) where TModel : IModel
Console.WriteLine("Testing model {0}:", model.GetType());
var dictionary = new Dictionary<string, string>()
[nameof(Model.SnakeCaseProperty)] = "snake_case_property",
var options = new JsonSerializerOptions
TypeInfoResolver = new DefaultJsonTypeInfoResolver
Modifiers = { JsonExtensions.RemapNames(typeof(TModel), dictionary) },
var json = JsonSerializer.Serialize(model, options);
Assert.AreEqual(json, @"{""PascalCaseProperty"":""PascalCase Value"",""snake_case_property"":""snake_case value""}");
var model2 = JsonSerializer.Deserialize<TModel>(json, options);
Assert.AreEqual(model.PascalCaseProperty, model2?.PascalCaseProperty);
Assert.AreEqual(model.SnakeCaseProperty, model2?.SnakeCaseProperty);
var json2 = JsonSerializer.Serialize(model2, options);
Assert.AreEqual(json, json2);
public static class ObjectExtensions
public static T ThrowOnNull<T>(this T? value) where T : class => value ?? throw new ArgumentNullException();
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: ");