Search code examples
c#.net-corejsonserializersystem.text.json

Get .NET Core JsonSerializer to serialize private members


I have a class with a private List<T> property which I would like to serialize/deserialize using the JsonSerializer. Use of the JsonPropertyAttribute doesn't seem to be supported in .NET Core. So how can I have my private list property serialized?

I'm using System.Text.Json for this.


Solution

  • It seems System.Text.Json does not support private property serialization.

    https://learn.microsoft.com/tr-tr/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to#internal-and-private-property-setters-and-getters

    But as the Microsoft's document says, you can do it with custom converters.

    https://www.thinktecture.com/en/asp-net/aspnet-core-3-0-custom-jsonconverter-for-the-new-system_text_json/

    Code snippet for serialization & deserialization;

      public class Category
        {
            public Category(List<string> names)
            {
                this.Names1 = names;
            }
    
            private List<string> Names1 { get; set; }
            public string Name2 { get; set; }
            public string Name3 { get; set; }
        }
    
    
     public class CategoryJsonConverter : JsonConverter<Category>
        {
            public override Category Read(ref Utf8JsonReader reader,
                                          Type typeToConvert,
                                          JsonSerializerOptions options)
            {
                           var name = reader.GetString();
    
                var source = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(name);
    
                var category = new Category(null);
    
                var categoryType = category.GetType();
                var categoryProps = categoryType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    
                foreach (var s in source.Keys)
                {
                    var categoryProp = categoryProps.FirstOrDefault(x => x.Name == s);
    
                    if (categoryProp != null)
                    {
                        var value = JsonSerializer.Deserialize(source[s].GetRawText(), categoryProp.PropertyType);
    
                        categoryType.InvokeMember(categoryProp.Name,
                            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance,
                            null,
                            category,
                            new object[] { value });
                    }
                }
    
                return category;
            }
    
            public override void Write(Utf8JsonWriter writer,
                                       Category value,
                                       JsonSerializerOptions options)
            {
                var props = value.GetType()
                                 .GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                 .ToDictionary(x => x.Name, x => x.GetValue(value));
    
                var ser = JsonSerializer.Serialize(props);
    
                writer.WriteStringValue(ser);
            }
        }
    
    static void Main(string[] args)
        {
            Category category = new Category(new List<string>() { "1" });
            category.Name2 = "2";
            category.Name3 = "3";
    
            var opt = new JsonSerializerOptions
            {
                Converters = { new CategoryJsonConverter() },
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            };
    
            var json = JsonSerializer.Serialize(category, opt);
    
            var obj = JsonSerializer.Deserialize<Category>(json, opt);
    
            Console.WriteLine(json);
            Console.ReadKey();
        }
    

    Result;

    "{\"Names1\":[\"1\"],\"Name2\":\"2\",\"Name3\":\"3\"}"