0

My WPF desktop application is attempting to use Ninject to inject some interface dependencies as follows. The app startup looks like this, (I think) auto-generated:

void App_Startup(object sender, StartupEventArgs e)
{
    IKernel _Kernel = new StandardKernel();
    _Kernel.Load(Assembly.GetExecutingAssembly());
}

I then have a NinjectModel-extending class whose Load method gets called by the above, and binding takes place like so:

Bind<Inheritance.IWindowProvider>().To<WindowProvider>().InSingletonScope();

My view models then take in an IWindowProvider and in this case I've also added the [Inject] attribute.

[Inject]
public LoginDetailsVM (IWindowProvider windowProvider) {
    this.WindowProvider = windowProvider;
}

Elsewhere then (in another VM), I want to make an instance of this view model:

IKernel kernel = new StandardKernel();
LoginDetailsVM loginDetails = kernel.Get<LoginDetailsVM>();

However I get the "dreaded" error:

Error activating IWindowProvider

No matching bindings are available, and the type is not self-bindable.

My initial search turns up that me instantiating StandardKernel twice is probably the issue, but I'm not sure how to access it otherwise.

Surely having to pass around an instance of the kernel somewhat defeats one of the points of having the injection?

Also, is the explicit Get<T>() form the accepted choice for obtaining instances, or is there a better implicit method of calling an injected constructor?

Apologies for what might seem a naive understanding here, I'm totally new to Ninject and DI generally.

Dan
  • 1,130
  • 2
  • 20
  • 38
  • Please include the source code for `WindowProvider` in your post. – mjwills Jul 24 '17 at 14:00
  • Does https://stackoverflow.com/a/38347614/34092 help? – mjwills Jul 24 '17 at 14:02
  • @mjwills `IWindowProvider` just contains two methods which are implemented by `WindowProvider` also containing a public blank constructor. I tried the linked article, but got a null reference exception. – Dan Jul 24 '17 at 14:21

2 Answers2

3

The problem isn't passing around the kernel - it's where you're accessing it. If you're referencing it outside of your composition root (App_Startup) then creating a new one isn't any better than passing around the one you already created.

When you need to resolve something outside of your composition root and you don't want to reference the container, one solution is to create a factory. Your component that needs to resolve something doesn't ask the container for it - it asks the factory for it.

The factory, in turn, is set up to resolve it from the container. But that's set up in your composition root, and the factory could be replaced with an implementation that doesn't involve the container. So you can still say that your component doesn't depend on or talk to the container.

Here's some documentation on configuring Ninject to supply an instance to a factory.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
0

Think of an IOC container like a magic dictionary with type and object instances stored in it.

If you did

Void a method (){
Var dictionary = new dictionary ();

dictionary.Add(typeof(IFOO), new Foo());
}

Void other_method(){

Var dictionary = new dictionary ();
IFOO instance =Dictionary[typeof(IFOO)];
// would you expect this to work?
}

Often the singleton pattern is used to provide access to an IOC container.

Dave
  • 11
  • 1