Trouble Serializing/Deserializing when using Interfaces and IoC

Jan 17, 2015 at 11:01 PM
I am trying to deserialize a json string that contains a number of collections that are based on interfaces. I have implemented an IContractResolver and am using an IoC container (TinyIoC) to resolve the interfaces into concrete classes -- the trouble I am running into is that nested collections do not seem to get populated with concrete classes with actual values.

Here is a sample.
namespace JsonIssue
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;

    using Newtonsoft.Json;
    using Newtonsoft.Json.Serialization;

    internal class Program
    {
        private static void Main(string[] args)
        {
            var container = new TinyIoC.TinyIoCContainer();

            container.Register<ISampleInterface1, SampleClass1>();
            container.Register<ISampleInterface2, SampleClass2>();
            container.Register<ISampleInterface3, SampleClass3>();

            var obj1 = new SampleClass1();
            for (int i = 0; i < 10; i++)
            {
                obj1.Items.Add(new SampleClass2 { Name = string.Format("Item {0}", i), Items = new List<ISampleInterface3> { new SampleClass3 { Name = "shawn 1"}} });
            }

            var js = new JsonSerializerSettings
                         {
                             TypeNameHandling = TypeNameHandling.None,
                             ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                             NullValueHandling = NullValueHandling.Ignore,
                             ContractResolver = new SampleContractResolver(container)
                         };

            var s = JsonConvert.SerializeObject(obj1);

            var r = JsonConvert.DeserializeObject<SampleClass1>(s, js);

            Debug.WriteLine(r);
        }
    }

    public interface ISampleInterface1
    {
        string Name { get; set; }

        ICollection<ISampleInterface2> Items { get; set; }
    }

    public interface ISampleInterface2
    {
        string Name { get; set; }

        ICollection<ISampleInterface3> Items { get; set; }
    }

    public interface ISampleInterface3
    {
        string Name { get; set; }
    }

    public class SampleClass1 : ISampleInterface1
    {
        public SampleClass1()
        {
            Items = new List<ISampleInterface2>();
        }

        public string Name { get; set; }

        public ICollection<ISampleInterface2> Items { get; set; }
    }

    public class SampleClass2 : ISampleInterface2
    {
        public SampleClass2()
        {
            Items = new List<ISampleInterface3>();
        }

        public string Name { get; set; }

        public ICollection<ISampleInterface3> Items { get; set; }
    }

    public class SampleClass3 : ISampleInterface3
    {
        public string Name { get; set; }
    }

    public class SampleContractResolver : DefaultContractResolver
    {
        private readonly TinyIoC.TinyIoCContainer _container;

        public SampleContractResolver(TinyIoC.TinyIoCContainer container)
        {
            _container = container;
        }

        public override JsonContract ResolveContract(Type type)
        {
            var contract = base.CreateObjectContract(type);

            if (this._container.CanResolve(type))
            {
                contract.DefaultCreator = () => this._container.Resolve(type);
            }

            return contract;
        }
    }
}