How to dynamically add new bindings using Ninject DI at runtime?

Therefore, I am trying to use a combination of MEF and Ninject in the application that I am writing. Basically I add extensions through MEF at runtime. I don't understand how (or if possible) I can update Ninject bindings at runtime.

For example, let's say I have the following element imported by MEF:

[Export(typeof(ICar))] public class BmwCar : ICar { private ICarLogger _carLogger; public BmwCar(ICarLogger carLogger) { _carLogger = carLogger; } public static string Type { get { return "Sedan"; } } public string GetBrand() { return "BMW"; } public static Type InterfaceType { get { return ICar; } } public static Type CarType { get { return GetType(); } } } 

Now that I knew this element at compile time, I could just create a Ninject module with the following links, for example:

 public class NinjectSetup : NinjectModule { public override void Load() { Bind<CarLogFactory>().ToSelf().InSingletonScope(); Bind<ICarLogger>().ToMethod(x => x.Kernel.Get<CarLogFactory>(new ConstructorArgument("vehicleName", BmwCar.Type)).WhenInjectedInto<BmwCar>(); } } 

So the problem is in this line:

 Bind<ICarLogger>().ToMethod(x => x.Kernel.Get<CarLogFactory>(new ConstructorArgument("vehicleName", BmwCar.Type)).WhenInjectedInto<BmwCar>(); 

I'm not sure how to add something like this dynamically after importing BmwCar. Obviously, I cannot use generic at runtime, since a type is needed at compile time. Since I cannot use generics at runtime, it seems something like:

 var binding = new BindingBuilder<ICarLogger>(new Binding(typeof(ICarLogger)), this.Kernel).ToMethod(x => x.Kernel.Get<CarLogFactory>(new ConstructorArgument("vehicleName", imported.Type)).WhenInjectedInto<imported.CarType>(); 

not an option. Does anyone know what to do to create new bindings at runtime?

+4
source share
3 answers

Yes, you can use the Bind or Rebind method available in the NInject kernel.

I don't know anything about MEF, but the code you want might look something like this:

 void OnApplicationStart() { StaticKernelContainer.Kernel = new StandardKernel(new YourInjectionModule()); } void AfterMEFHasDoneWhatItNeedsToDo() { // (You may need to use Rebind at this point) StaticKernelContainer.Kernel.Bind<ICarLogger>().To(importer.CarType); } 
+3
source

Are you sure you cannot do something cleaner, for example. through the injection method ?

Also read the CreateLog example on the context binding wiki

I'm not sure if you need to make stacks of Bind<> calls or add many static helper classes like yours.

Or maybe I just read it wrong - can you expand your example a bit; I just don’t understand how to be honest?

+1
source

Here is a solution that does not rely on MEF, but should do what you want to achieve.

 // Plugin interface assembly defines interface ICarInfoProvider { IEnumerable<string> CarTypes { get; } } // Plugin Bmw Assembly defines public class BmwPluginCarInfoProvider : ICarInfoProvider { IEnumerable<string> CarTypes { get { return new List<string> { "Sedan", "3", "5" }; } } } public class BmwPluginModule : NinjectModule { public override Load() { // Or use ctor to define car name this.Bind<ICarInfoProvider>().To<BmwPluginCarInfoProvider>(); this.Bind<ICar>().To<BmwCar>().Named("Sedan").OnActivation(car => car.Name = "Sedan"); this.Bind<ICar>().To<BmwCar>().Named("3").OnActivation(car => car.Name = "3"); this.Bind<ICar>().To<BmwCar>().Named("5").OnActivation(car => car.Name = "5"); } } // Plugin Toyota Assembly defines public class ToyotaPluginCarInfoProvider : ICarInfoProvider { IEnumerable<string> CarTypes { get { return new List<string> { "Yaris", "Prius", }; } } } public class ToyotaPluginModule : NinjectModule { public override Load() { // Or use ctor to define car name this.Bind<ICarInfoProvider>().To<ToyotaPluginCarInfoProvider>(); this.Bind<ICar>().To<ToyotaCar>().Named("Yaris").OnActivation(car => car.Name = "Yaris"); this.Bind<ICar>().To<ToyotaCar>().Named("Prius").OnActivation(car => car.Name = "Prius"); } } // Application var kernel = new StandardKernel(new NinjectSettings { // Ensure here that assembly scanning is activated }); public class NinjectSetup : NinjectModule { public override void Load() { Bind<CarLogFactory>().ToSelf().InSingletonScope(); // Sorry for being vague here but I'm in a hurry Bind<ICarLogger>().ToMethod(x => x.ContextPreservingGet<CarLogFactory>(new ConstructorArgument("vehicleName", ctx => // access here named parameter or use own parameter to get name //).CreateLogger()); } } // Somewhere in your code var infos = resolutionRoot.GetAll<ICarInfoProvider>(); // User chooses "Sedan" var sedan = resolutionRoot.Get<ICar>("Sedan"); 
+1
source

Source: https://habr.com/ru/post/1345979/


All Articles