Is there a way to get dependency injection with a JsonConverter derived custom converter
Asked Answered
K

1

8

Not quite the same as this:

How do I Inject Dependencies with Ninject, where instances are deserialised from json

Where the answer is that your data class that you deserialized shouldn't need a service anyway. Is there a way to use dependency inject with a class derived from JsonConverter? For example, if you had this:

[JsonConverter(typeof(MyCustomConverter))]
public class Foo
{
    public string SomeProp { get; set; }
}

And:

public class MyCustomConverter : JsonConverter
{
    private readonly IMyService myService;

    public MyCustomConverter(IMyService _myService)
    {
        myService = _myService;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var bar = myService.SomeFunctionThatMightEffectDeserialization();
        //...
    }
}

Is there anyway to hook into how JSON.Net instantiates MyCustomConverter to get it to let Ninject do it's thing?

EDIT This is NOT injecting a service into Foo like the suggested dupe. This is injecting only into MyCustomConverter so that it can then deserialize Foo.

Kaenel answered 10/8, 2015 at 19:36 Comment(11)
@StriplingWarrior: The duplicate isn't quite the same. I'm not looking to inject into the object I'm deserializing. The object I'm deserializing doesn't need any services, only the json converter needs dependency injection.Kaenel
Could you add some static (thread static?) event to your MyCustomConverter type that allows an IMyService to be returned in custom event args. Awkward, but doable. Also, maybe see here: blog.ploeh.dk/2013/09/08/di-and-events-third-party-connectDowel
@dbc: An interesting idea, I'd have to think about that one.Kaenel
@MattBurland: Nevermind, you're right. Carry on.Appendicectomy
what creates the converter? that would be responsible for injecting the dependenciesEslinger
@davethieben quite obviously newtonsoft.jsonDennard
@davethieben: Well that's the question. The JsonConverterAttribute is sealed, so I can't derive. Somewhere in the internal workings of JSON.Net that attribute gets read when it tries to deserialize that class and an instance of MyCustomConverter gets created. The key part of the question is whether or not there's a place to hook into that process.Kaenel
@MattBurland I don't think you can do it without accessing the kernel, which really should not be accessed outside of composition root. json.net does not support participating in a DI pipeline, so all you left with is workarounds.Dennard
@MattBurland JsonTypeReflector is the class responsible for the instantication, if you'd like to have a look.Dennard
@MattBurland - Have a look at this answer. If you define attributes without behavior, you can use a class with behavior (that is injected with DI) to read their metadata.Demineralize
@NightOwl888: I've seen (and used) similar stuff with filters using BindHttpFilter in ninject, but I'm not sure if it's generally possible. I need the attribute JsonConverter(typeof(MyCustomConverter)) for JSON.Net, but I need json.net to let DI construct the instance of MyCustomConverter and that seems to be buried in JsonTypeReflector which is internal staticKaenel
K
1

It's a bit of a hack, but it's possible to do something similar by setting the ContractResolver in the JsonSerializerSettings. In this case, using Autofac:

var builder = new ContainerBuilder();
builder.RegisterInstance(myService);
var container = builder.Build();

var settings = new JsonSerializerSettings
{
    ContractResolver = new AutofacContractResolver(container),
};

and then in the converter:

var jsonContract = serializer.ContractResolver.ResolveContract(typeof(IMyService));
var service = (IMyService)jsonContract.DefaultCreator();

So you're not really injecting the service into the converter, but at least you can access it without a concrete dependency. Also you're not using the same Autofac container as your app but creating a new one. Not ideal, but it's something :)

Kerwinn answered 8/11, 2016 at 10:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.