自定义Json转换器与构造函数参数

时间:2017-02-18 01:12:14

标签: json dependency-injection converter autofac

我正在尝试创建一个没有默认构造函数的自定义Json转换器,而是使用由Autofac注入的依赖项的工厂。当我点击使用此转换器的对象时,我得到一个异常,即没有用于反序列化的无参数构造函数。

我有一个对象和原语。其中一个对象是我有转换器的抽象基础对象。由于这个转换器是抽象的,我想依赖注入工厂到转换器的ReadJson方法,以选择要进行的转换。

目前代码如下:

using System;
using System.Collections.Generic;

using Autofac;

using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;

using Newtonsoft = Newtonsoft.Json;

public class JsonModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<SubThingFactory>()
            .As<IFactory>()
            .SingleInstance();

        builder.Register(c => this.CreateJsonSerializerSettings(c)).SingleInstance();

        builder.RegisterType<CamelCasePropertyNamesContractResolver>()
            .As<IContractResolver>()
            .SingleInstance();

        builder.RegisterType<IsoDateTimeConverter>()
            .As<Newtonsoft.JsonConverter>()
            .SingleInstance();

        builder.RegisterType<SubThingConverter>()
            .As<Newtonsoft.JsonConverter>()
            .SingleInstance();

        builder.Register(c => new StringEnumConverter
        {
            CamelCaseText = true
        })
            .As<Newtonsoft.JsonConverter>()
            .SingleInstance();
    }

    private Newtonsoft.JsonSerializerSettings CreateJsonSerializerSettings(IComponentContext context)
    {
        var settings = new Newtonsoft.JsonSerializerSettings
        {
            DefaultValueHandling = Newtonsoft.DefaultValueHandling.Ignore,
            NullValueHandling = Newtonsoft.NullValueHandling.Ignore,
            DateTimeZoneHandling = Newtonsoft.DateTimeZoneHandling.Utc
        };

        settings.ContractResolver = context.Resolve<IContractResolver>();

        foreach (var converter in context.Resolve<IEnumerable<Newtonsoft.JsonConverter>>())
        {
            settings.Converters.Add(converter);
        }

        return settings;
    }
}

public class ThingBeingDeserialized
{
    private string Name;
    private SubThing subby;
}

[Newtonsoft.JsonConverterAttribute(typeof(SubThingConverter))]
public abstract class SubThing
{
    public string Name { get; set; }

    public virtual string GetName()
    {
        //Uses reflection to get the name from a custom attribute
        return this.Name;
    }
}

[CustomName("A")]
public class SubThingA : SubThing
{
    public int Field1 { get; set; }
}

[CustomName("B")]
public class SubThingB : SubThing
{
    public string Field2 { get; set; }
}

public class SubThingConverter : Newtonsoft.JsonConverter
{
    //This is Autofac injected in
    private readonly IFactory factory;

    public SubThingConverter(IFactory factory)
    {
        this.factory = factory;
    }

    public override object ReadJson(Newtonsoft.JsonReader reader, Type objectType, object existingValue, Newtonsoft.JsonSerializer serializer)
    {
        if (reader.TokenType == Newtonsoft.JsonToken.Null)
        {
            return null;
        }

        var jsonObject = JObject.Load(reader);

        var type = jsonObject["type"].ToString();

        return this.factory.GetSubThing(type, jsonObject);
    }

    public override void WriteJson(Newtonsoft.JsonWriter writer, object value, Newtonsoft.JsonSerializer serializer)
    {
        var type = value.GetType();
        var properties = type.GetProperties();

        var jObject = new JObject
        {
            { "type", type.Name }
        };

        foreach (var prop in properties)
        {
            if (prop.CanRead)
            {
                var propVal = prop.GetValue(value, null);
                if (propVal != null)
                {
                    jObject.Add(prop.Name, JToken.FromObject(propVal, serializer));
                }
            }
        }

        jObject.WriteTo(writer);
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(SubThing);
    }
}

public interface IFactory
{
    SubThing GetSubThing(string type, JObject restOfObj);
}

public class SubThingFactory : IFactory
{
    public SubThing GetSubThing(string type, JObject restOfObj)
    {
        switch (type)
        {
            case "A":
                return new SubThingA
                {
                    Field1 = (int)(restOfObj["Field1"])
                };
            case "B":
                return new SubThingB
                {
                    Field2 = (string)(restOfObj["Field2"])
                };
        }

        return null;
    }
}

public class CustomNameAttribute : Attribute
{
    public CustomNameAttribute(string name)
    {
        this.Name = name;
    }

    public string Name { get; set; }
}

我为JsonSerializerSettings进行Autofac注入的方法是注册设置,以便settings.Converters将获取在Autofac容器中注册的所有JsonConverters的枚举,并注册SubThingConverter,以便在已解决它将解决它的IFactory和JsonSerializer也来自具有这些设置的autofac容器。

即使我跳过依赖注入并使用带有JsonSerializerSettings的新JsonSerializer并将自定义转换器添加为

settings.Converters.Add(new SubThingConverter(new SubThingFactory()))

我仍然抱怨SubThingConverter没有没有arg构造函数。

在我看来,覆盖设置以明确使用此转换器应该就足够了。我也尝试在SubThing的JsonConverter属性中添加object [] params,我无法使它工作,它似乎需要是一个编译时数组,这不适用于我需要的依赖注入做。任何指针都将非常感激。谢谢!

0 个答案:

没有答案