I need more Ninject practical examples
Asked Answered
R

2

8

In the past, I used swiftsuspenders that is an actionscript 3 IoC controller. Basically the first version of switfsuspender had something similar to the Ninject kernel that was called injector.

If I wanted to create an application injector (with let's say the most relevant mappings to be used throughout the application), I had to inject the injector itself in the application classes.

I am wondering now what is the practice to use kernel.get<> among several classes in the application. Should I inject the kernel itself?

Personally I'd rather use kernel.inject but if I can do kernel.inject I can really likely inject the dependencies manually, which is probably better (kiss).

Test cases are nice, but they are far from the real practical issues, so I hope you can help me to clarify this point. Thank you.

Edit: I noticed that some people talk about "root container", It seems like it is the concept I am looking for. How should I setup a root container and let the other application classes know it?

Edit2 Sample code (please forgive errors, it is just for example sake):

class SomeClass
{
    public SomeClass()
    {
        Command cmd = new Command();

        cmd.execute();
    }

}

class SomeOtherClass:ISomeOtherClass
{
 public void allright()
 {
    //right
 }
}

class Command
{
   ISomeOtherClass dependency;

   void execute()
   {
    dependency.allright();
   }

}


Program.Main()
{
    IKernel kernel = new StandardKernel();

    kernel.Bind<SomeClass>().ToSelf().InSingletonScope();
    kernel.Bind<ISomeOtherClass>().To<SomeOtherClass>();

    SomeClass sc = kernel.Get<SomeClass>();
}

I did not test this yet, because I am still fighting with some initialization issues, but my question is, how can the command class know about SomeOtherClass? My current hypothesis is to inject the kernel in SomeClass and use the method Inject.

Regent answered 7/2, 2012 at 17:27 Comment(0)
D
11

Looking at your example, it is clear that SomeClass is not built with Inversion of Control in mind; the tip-off being that it has a dependency on Command, but control of that dependency is maintained inside SomeClass itself. (Command cmd = new Command();)

To invert the control of that dependency, you would need to have a way to inject that dependency into SomeClass. As Remo Gloor has indicated, the standard way of doing that with Ninject is through the constructor.

To do so, you might change SomeClass to something like this:

class SomeClass
{
    private ICommand _command;

    public SomeClass(ICommand injectedCommand)
    {
        _command = injectedCommand;
        _command.execute();
    }

}

Likewise you would need your Command to advertise its dependency:

class Command
{
   private ISomeOtherClass _dependency;

   public Command(ISomeOtherClass injectedSomeOtherClass)
   {
        _dependency = injectedSomeOtherClass;
   {

   void execute()
   {
      _dependency.allright();
   }
}

Then you would register your Command binding in the kernel, perhaps like:

Program.Main()
{
    IKernel kernel = new StandardKernel();

    kernel.Bind<SomeClass>().ToSelf().InSingletonScope();
    kernel.Bind<ICommand>().To<Command>();
    kernel.Bind<ISomeOtherClass>().To<SomeOtherClass>();

    SomeClass sc = kernel.Get<SomeClass>();
}

The kernel would then be able to walk the dependency chain and inject them all.

Diagenesis answered 8/2, 2012 at 18:20 Comment(9)
Thanks for the answer it makes sense, but while it is correct, it just states that all the dependencies must be known beforehand. What happens when this is not possible? (of course what I say makes sense only if objects are created dynamically which could happen)Regent
let's say that SomeClass must create a definitive number of dynamic objects. Like SomeClass become Level and it must create 30 stars. the stars have some dependencies, how can Level inject those dependencies to the stars using the kernel?Regent
That's a good question, and you're moving beyond simple dependency injection questions that can be answered in this format. This kind of situation (complex object creation) tends to require one more piece, which is why Remo mentioned Factories in his answer. You should investigate either creating a star-building factory and inject that into SomeClass, or have Ninject resolve the stars using a factory method itself or Bind().ToProvider().Diagenesis
ok so a waterfall injection of the kernel would not make any sense because there are better much better ways provided. Thanks again for the help.Regent
+1 This shows exactly how it should be done and reflects exactly the initial sentense of my answer. Make sure you give the example from the beginning next time. It makes it much easier to see where your problem lies.Verina
Thanks Remo. I have just one question for @EricKing: you were talking about IoC like if it was something directly related to DI. If I am not wrong, IoC says how to invert the control flow of the application, then DI is just one consequence of doing it. However in my example, I do not see any IoC passing the command as parameter.Regent
@Regent The IoC principle says that you should invert control, but not how. One of the strategies for the how is dependency injection, and one version of dependency injection is constructor injection (you could also do it through property injection, and there are probably several other ways, too). In your example, the dependency (Command) is not injected at all, through the constructor or otherwise. Control flow is not inverted in any way, as SomeClass maintains complete control over the construction of its dependency. There is no IoC in that aspect of your example.Diagenesis
@EricKing I always thought that IoC and the Hollywood principle were strictly correlated, so IoC actually meant more let the framework handle your objects, than the other way around. That is the reason of my question.Regent
@Regent No, I think they are two completely separate principles. The Hollywood principle is more about separation of concerns; a way of keeping classes from becoming too interdependent on each other. IoC is more about managing the dependencies themselves, their creation and their lifecycles. There's a good description of both principles and their relationship in the book "Head First Design Patterns", if you want to check that out.Diagenesis
V
5

Use constructor injection wherever possible and Factories whenever there is a good reason not to create the instances together with the object that depend on them.

kernel.Inject should only be used when you are not in change of the creation of the object. E.g. a WebForm

kernel.Get should be used exactly once in your composition root (e.g. Program.Main or MVC3.DependencyResolver) to create your application.

Verina answered 7/2, 2012 at 19:49 Comment(3)
Hi Remo! Thank you for the answer. You provided useful information, but it is not what I wanted to know. You are telling me that Get should not be used as service locator, but what I asked was more this: Let's say I have a class that needs to create a command in one of its method. Let's say that the command needs some dependencies injected and the kernel has been defined outside the class which creates the command. How should I use the kernel to inject the dependencies inside this command? Should I first inject the kernel in the class which creates the command?Regent
my Problem is something similar to this #2863198 but I would not use any static class, I prefer to inject the kernel at this point.Regent
You should add a code example to your question of what you want to do. Everything else is just guessing. Normally dependencies should be passed using constructor injection which is done automatically by Ninject.Verina

© 2022 - 2024 — McMap. All rights reserved.