skip to Main Content

I’m removing Newtonsoft.Json from a project and replace it with an implementation of System.Text.Json.Serialization.

The old model uses a JsonArrayAttribute in combination with CustomCreationConverter<T>.

class JsonListItemConverter<TListItem>:
    CustomCreationConverter<TListItem>
{
    public override TListItem Create( Type objectType )
    {
        return ( TListItem ) FormatterServices.GetSafeUninitializedObject( typeof( TListItem ) );
    }
}

interface FooInterface
{
    string Value { get; set; }
}

class Foo:
    FooInterface
{
  public virtual string Value { get; set; }
}

interface BarInterface
{
    virtual IList<FooInterface> { get; set; }
}

class Bar:
    BarInterface
{
    [JsonArray( ItemConverterType = typeof( JsonListItemConverter<Foo> ) )]
    public virtual IList<FooInterface> { get; set; }
}

This still enables me to implement against interfaces but deserializes concrete classes.

I’m now looking for an equivalent in System.Net.Json to replace the now unkown JsonArrayAttribute.

I assume I’d use JsonConverter. I found out there’re several converters in System.Text.Json.Serialization.Converters, like the ListOfTConverter<TCollection, TElement>. But they are all internal and they are for serializing only.

I’m looking for a solution to deserialize a JSON array into a strongly interfaced collection type like IList<FooInterface>.

2

Answers


  1. You are trying to replace Newtonsoft.Json with System.Text.Json and need to deserialize a JSON array into an IList<FooInterface>. Since System.Text.Json doesn’t support deserializing interfaces out of the box, you’ll need to create a custom converter.

    using System;
    using System.Collections.Generic;
    using System.Text.Json;
    using System.Text.Json.Serialization;
    
    namespace DeserializeInterfaces
    {    
        public interface FooInterface
        {
            string Value { get; set; }
        }
    
        public interface BarInterface
        {
            IList<FooInterface> Foos { get; set; }
        }
       
        public class Foo : FooInterface
        {
            public string Value { get; set; }
        }
    
        public class Bar : BarInterface
        {
            [JsonConverter(typeof(InterfaceListConverter<FooInterface, Foo>))]
            public IList<FooInterface> Foos { get; set; }
        }
       
        public class InterfaceListConverter<TInterface, TImplementation> : JsonConverter<IList<TInterface>>
            where TImplementation : TInterface, new()
        {
            public override IList<TInterface> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {            
                var list = JsonSerializer.Deserialize<List<TImplementation>>(ref reader, options);
                return list != null ? new List<TInterface>(list) : null;
            }
    
            public override void Write(Utf8JsonWriter writer, IList<TInterface> value, JsonSerializerOptions options)    
        {           
                JsonSerializer.Serialize(writer, (List<TImplementation>)value, options);
            }
        }
    
     
        class Program
        {
            static void Main(string[] args)
            {
                var json = @"{ ""Foos"": [ { ""Value"": ""Item1"" }, { ""Value"": ""Item2"" } ] }";
    
                var bar = JsonSerializer.Deserialize<Bar>(json);
    
                foreach (var foo in bar.Foos)
                {
                    Console.WriteLine(foo.Value);
                }         
            }
        }
    }
    

    Explanation:

    System.Text.Json doesn’t natively support deserializing to interface types. By creating a custom converter, you guide the deserialization process to use the concrete class while allowing your code to work with the interface. Some useful tools to visually check Complex JSON.

    Login or Signup to reply.
  2. In System.Text.Json, to deserialize a JSON array into a strongly typed collection such as IList<FooInterface>, you can utilize a custom converter that implements the JsonConverter abstract class.

    Here is an example implementation to achieve this:

    1. Create a custom converter class that inherits from JsonConverter<IList<FooInterface>>:
    public class FooInterfaceListConverter : JsonConverter<IList<FooInterface>>
    {
        public override IList<FooInterface> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            using (JsonDocument doc = JsonDocument.ParseValue(ref reader))
            {
                var root = doc.RootElement;
                
                List<FooInterface> list = new List<FooInterface>();
                foreach (var element in root.EnumerateArray())
                {
                    FooInterface foo = JsonSerializer.Deserialize<Foo>(element.GetRawText(), options); // Deserialize each element as Foo
                    list.Add(foo);
                }
                
                return list;
            }
        }
    
        public override void Write(Utf8JsonWriter writer, IList<FooInterface> value, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }
    }
    
    1. Apply the custom converter to the IList<FooInterface> property in your class:
    class Bar : BarInterface
    {
        [JsonConverter(typeof(FooInterfaceListConverter))]
        public IList<FooInterface> FooList { get; set; }
    }
    

    By using a custom JsonConverter that reads the JSON array elements and deserializes each element into a Foo object, you can achieve the desired behavior of deserializing a JSON array into a strongly interfaced collection type like IList<FooInterface>.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search