Search code examples
c#jsondependency-injectionjson.netninject

How can Json.NET perform dependency injection during deserialization?


When I have a class with no default constructor, i.e. using dependency injection to pass its dependencies, can Newtonsoft.Json create such an object?

For example:

public class SomeFoo
{
    private readonly IFooDependency _dependency;

    public SomeFoo(IFooDependency dependency){
        if(dependency == null)
            throw new ArgumentNullException("dependency");

        _dependency = dependency;
    }

    public string Data { get; set; }
    public int MoreData { get; set; }

    public void DoFoo(){
        Data = _dependency.GetFooData();
        MoreData = _dependency.GetMoreFooDate();
    }
}

During serialization, I only care of storing Data and MoreData (and the type of the object, but let's don't complicate things for the moment). Now, to deserialize, can I call something like

var obj = JsonConvert.DeserializeObject<SomeFoo>(jsonText);

How can I let JsonConvert know about my DI container?

(Note: A work-around would be to always have default constructors in my classes, and call Service Locator in there to get any dependencies I need. I'm just looking for some more clean solution without poluting my classes with such constructors).


Solution

  • I agree with the separation of concerns posted by Steven, and the answer Mark Seemann has posted here. However, if you still want to go this way, here is a solution that may help:

    Inherit a CustomCreationConverter<T>:

    internal class NinjectCustomConverter<T> : CustomCreationConverter<T> where T : class
    {
        private readonly IResolutionRoot _serviceLocator;
    
        public NinjectCustomConverter(IResolutionRoot serviceLocator)
        {
            _serviceLocator = serviceLocator;
        }
    
        public override T Create(Type objectType)
        {
            return _serviceLocator.Get(objectType) as T;
        }
    }
    

    Then make sure you retrieve this converter instance via your DI container as well. The code below will deserialize and perform DI on your object:

    var ninjectConverter = kernel.Get<NinjectCustomConverter<SerializedObject>>();
    var settings = new JsonSerializerSettings();
    settings.Converters.Add(ninjectConverter);
    
    var instance = JsonConvert.DeserializeObject<SerializedObject>(json, settings);
    

    Here is a complete working example.