0

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>.

1

1 Answer 1

0

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.