How to Use Ninject

17,546

Solution 1

First of all do I need to use the Inject attribute on all constructors that I want to use injection for. This seems like a really lame design?

No you shouldn't have to do this at all actually. Since you work with ASP.NET MVC you can just install the Ninject.MVC3 Nuget package. This will get you started with a NinjectMVC3 class in the App_Start folder. You can use the RegisterServices method to register your interfaces/classes with Ninject. All controllers that have dependencies to those interfaces will then be automatically resolved by Ninject, there is no need for the Inject attribute.

Do I need to create a Kernel then use that everywhere I pass in an injected class?

No - what you are describing sounds more like the Service Locator pattern, not dependency injection - you will want to pass in your dependencies ideally in the constructor, instead of resolving them within particular classes using the kernel. There should be just one central composition root where the resolving is done, which is within the composition root in either the RegisterServices method mentioned above or a separate Ninject module instantiated there - the later approach will allow you a little more flexibility and modularity (no pun intended) in changing how you resolve your dependencies.

Here's a good beginner's tutorial on dependency injection with Ninject and MVC3.

Solution 2

The best way to get started with Ninject is to start small. Look for a new.

Somewhere in the middle of your application, you're creating a class inside another class. That means you're creating a dependency. Dependency Injection is about passing in those dependencies, usually through the constructor, instead of embedding them.

Say you have a class like this, used to automatically create a specific type of note in Word. (This is similar to a project I've done at work recently.)

class NoteCreator
{
    public NoteHost Create()
    {
        var docCreator = new WordDocumentCreator();
        docCreator.CreateNewDocument();
        [etc.]

WordDocumentCreator is a class that handles the specifics of creating a new document in Microsoft Word (create an instance of Word, etc.). My class, NoteCreator, depends on WordDocumentCreator to perform its work.

The trouble is, if someday we decide to move to a superior word processor, I have to go find all the places where WordDocumentCreator is instantiated and change them to instantiate WordPerfectDocumentCreator instead.

Now imagine that I change my class to look like this:

class NoteCreator
{
    WordDocumentCreator docCreator;

    public NoteCreator(WordDocumentCreator docCreator)  // constructor injection
    {
        this.docCreator = docCreator;
    }

    public NoteHost Create()
    {
        docCreator.CreateNewDocument();
        [etc.]

My code hasn't changed that much; all I've done within the Create method is remove the line with the new. But now I'm injecting my dependency. Let's make one more small change:

class NoteCreator
{
    IDocumentCreator docCreator;

    public NoteCreator(IDocumentCreator docCreator)  // change to interface
    {
        this.docCreator = docCreator;
    }

    public NoteHost Create()
    {
        docCreator.CreateNewDocument();
        [etc.]

Instead of passing in a concrete WordDocumentCreator, I've extracted an IDocumentCreator interface with a CreateNewDocument method. Now I can pass in any class that implements that interface, and all NoteCreator has to do is call the method it knows about.

Now the tricky part. I should now have a compile error in my app, because somewhere I was creating NoteCreator with a parameterless constructor that no longer exists. Now I need to pull out that dependency as well. In other words, I go through the same process as above, but now I'm applying it to the class that creates a new NoteCreator. When you start extracting dependencies, you'll find that they tend to "bubble up" to the root of your application, which is the only place where you should have a reference to your DI container (e.g. Ninject).

The other thing I need to do is configure Ninject. The essential piece is a class that looks like this:

class MyAppModule : NinjectModule
{
    public override void Load()
    {
        Bind<IDocumentCreator>()
            .To<WordDocumentCreator>();

This tells Ninject that when I attempt to create a class that, somewhere down the line, requires an IDocumentCreator, it should create a WordDocumentCreator and use that. The process Ninject goes through looks something like this:

  • Create the application's MainWindow. Its constructor requires a NoteCreator.
  • OK, so create a NoteCreator. But its constructor requires an IDocumentCreator.
  • My configuration says that for an IDocumentCreator, I should use WordDocumentCreator. So create a WordDocumentCreator.
  • Now I can pass the WordDocumentCreator to the NoteCreator.
  • And now I can pass that NoteCreator to the MainWindow.

The beauty of this system is threefold.

First, if you fail to configure something, you'll know right away, because your objects are created as soon as your application is run. Ninject will give you a helpful error message saying that your IDocumentCreator (for instance) can't be resolved.

Second, if management later mandates the user of a superior word processor, all you have to do is

  • Write a WordPerfectDocumentCreator that implements IDocumentCreator.
  • Change MyAppModule above, binding IDocumentCreator to WordPerfectDocumentCreator instead.

Third, if I want to test my NoteCreator, I don't have to pass in a real WordDocumentCreator (or whatever I'm using). I can pass in a fake one. That way I can write a test that assumes my IDocumentCreator works correctly, and only tests the moving parts in NoteCreator itself. My fake IDocumentCreator will do nothing but return the correct response, and my test will make sure that NoteCreator does the right thing.

For more information about how to structure your applications this way, have a look at Mark Seemann's recent book, Dependency Injection in .NET. Unfortunately, it doesn't cover Ninject, but it does cover a number of other DI frameworks, and it talks about how to structure your application in the way I've described above.

Also have a look at Working Effectively With Legacy Code, by Michael Feathers. He talks about the testing side of the above: how to break out interfaces and pass in fakes for the purpose of isolating behavior and getting it under test.

Solution 3

Don't forget there are docs, including an intro I feel would be very appropriate given the sort of questions you are asking on the Ninject Wiki. You're just annoying yourself if you're trying to use Ninject without reading it end to end.

Stick the table of contents on your bookmark bar for a bit.

I can also highly recommend Mark Seemann's Dependency Injection in .Net as a companion book for DI based architecture (even though it doesnt directly cover Ninject).

Share:
17,546

Related videos on Youtube

Sachin Kainth
Author by

Sachin Kainth

I am a senior C#, .NET and AngularJS developer living in London.

Updated on June 01, 2022

Comments

  • Sachin Kainth
    Sachin Kainth almost 2 years

    I have been trying to use Ninject today and have a couple of questions. First of all do I need to use the Inject attribute on all constructors that I want to use injection for. This seems like a really lame design? Do I need to create a Kernel then use that everywhere I pass in an injected class?

  • Sachin Kainth
    Sachin Kainth over 12 years
    Thanks for this information. I've now removed the [Inject] attribute. I watched a tutorial video and that's where I learned to do that. What I need to do now is pass parameters into the resolved concreate class for which I'm using WithConstructorArgument but I still get this error: No parameterless constructor defined for this object.
  • Sachin Kainth
    Sachin Kainth over 12 years
    Plus, I'm confused now, the link you posted also uses the StandardKerbal approach. My understanding of DI was that the container automatically resolved dependancies (depending on the bindings you set up).
  • BrokenGlass
    BrokenGlass over 12 years
    @Sachi: You do not need WithConstructorArgument() either if the parameters that need to be passed are resolved with Ninject as well - think of it as a graph
  • Tarik
    Tarik about 11 years
    Really nice explaination for both Dependency Injection as well as Ninject! Thanks and I am copying it to my Evernote for further references.
  • Zo Has
    Zo Has about 10 years
    @Kyralessa That is really an excellent explanation. One of the best which I have read so far, clear and consise. What you are doing in the start is called as Poor man's Dependecy injection?
  • Luis Pena
    Luis Pena almost 9 years
    Wow best explanation i've seen so far give this man a potato. +1