简体   繁体   中英

Better way to resolve the binding of multiple services when the context is the same in Ninject?

I've got a class that has a factory method, which when it finds a serialized version of itself should return it; otherwise it should return a new instance of itself:

class ClassToDeserialize : List<SomeClass>
{
    public static event Func<ClassToDeserialize> onNoDeserializationFile;

    public ClassToDeserialize(SomeClass firstInList)
    {
        this.Add(firstInList);
    }

    public static ClassToDeserialize DeserializeIfAny(string jsonPath)
    {
        if (File.Exists(jsonPath))
            return JsonConvert.DeserializeObject<ClassToDeserialize>(File.ReadAllText(jsonPath));

        return onNoDeserializationFile();
    }
}

I'm trying to refactor my application to use DI, the problem though is that I have to do a double binding for ClassToDeserialize, like so:

static void Main(string[] args)
    {
        string json = @"C:\obj_serialized.txt";
        IKernel ninjectKernel = new StandardKernel();
        ClassToDeserialize.onNoDeserializationFile += (() => ninjectKernel.Get<ClassToDeserialize>("NoSerialization"));

        ninjectKernel.Bind<ClassToDeserialize>().ToSelf().Named("NoSerialization").WithConstructorArgument("jsonPath", json);
        ninjectKernel.Bind<ClassToDeserialize>().ToConstant<ClassToDeserialize>(ClassToDeserialize.DeserializeIfAny(json));
    }

I added the onNoDeserializationFile event to let ninject handle all instantiations and decouple my business logic from my IoC, and then I intend to Get a Service which has a dependency upon ClassToDeserialize, and to be able to resolve this request I need to find a way to tell ninject that when a serialization file is found it should call the corresponding binding (even though the context is the same).

ninjectKernel.Get<DependantClass>().DoSomething();

I'm aware this resembles the Service-Locator Antipattern, but is not the only way I'm using the container and this behavior is tied only to the entry point of my application.

What's the proper way for solving this?

You could put that decision logic into an IProvider .

Alternatively there's the When binding syntax for conditions. See Contextual Bindings .

How about using:

kernel.Bind<ClassToDeserialize>().ToSelf()
      .WithConstructorArgument(...); // default binding

kernel.Bind<ClassToDeserialize>()
      .ToMethod(ctx => JsonConvert.DeserializeObject<ClassToDeserialize>(...))
      .InSingletonScope()
      .When(ctx => File.Exists(...));

(hint: i didn't compile it so the method sequence might be slightly off).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM