Dependency Injection (DI) – Hello World with Ninject

“Stop writing monolithic applications that make you feel like you have to move mountains to make the simplest of changes. Ninject helps you use the technique of dependency injection to break your applications into loosely-coupled, highly-cohesive components, and then glue them back together in a flexible manner.” - www.ninject.org

Wait. First tell me what on earth is Dependency Injection or DI in short?

Dependency injection (DI) in object-oriented computer programming is a technique for supplying an external dependency (i.e. a reference) to a software component - that is, indicating to a part of a program which other parts it can use. (source: Wikipedia)

In short “loose coupling”.

I am going to start with explaining a simple scenario where we could use the DI pattern. I will be using Ninject to write dependency injections. If you want to try other frameworks, Scott Hanselman has a great list of them for .net here.

Let’s say we need to create a software called XDoc which is a word text editor. And we will implement a part of it which is able to write to different mediums – console (stdout), file, pdf file, doc file and so on…

To solve the above problem, we would first define a interface or abstract class.

namespace Prabir.NinjectSample.Provider
{
    public interface IWriter
    {
        void Write(string str);
        void Write(int i);
    }
}

For simplicity, I will just add those 2 methods. I prefer to put in under the namespace Provider but that’s all up to you.

Now, lets create the implementation of it. In this tutorial we will create two. One to write in console and one to show in message box (not really a text editor).

using System;
using Prabir.NinjectSample.Provider;

namespace Prabir.NinjectSamples.Providers.ConsoleWriter
{
    public class ConsoleWriter : IWriter
    {
        public void Write(string str)
        {
            Console.Write(str);
        }

        public void Write(int i)
        {
            Console.Write(i);
        }
    }
}

Implementation is done just in the plain old style. Nothing new.

using System.Windows.Forms;
using Prabir.NinjectSample.Provider;

namespace Prabir.NinjectSample.Providers.MessageBoxWriter
{
    public class MessageBoxWriter : IWriter
    {
        public void Write(string str)
        {
            MessageBox.Show(str);
        }

        public void Write(int i)
        {
            MessageBox.Show(i.ToString());
        }
    }
}

Then we create a class that holds the instance of the Writer – either ConsoleWriter or MessageBoxWriter.

using Ninject;

namespace Prabir.NinjectSample.Provider
{
    public class XDoc
    {
        private IWriter _writer;
        public IWriter Writer { get { return _writer; } }

        [Inject]
        public XDoc(IWriter writer)
        {
            _writer = writer;
        }
    }
}

Notice something new, I use a [Inject] attribute to tell Ninject to inject something (something will be described later on). This is known as constructor injection. Other types of injections also exists – property injection and method injection.

Many DI frameworks use xml mapping to inject which become quite cumbersome over time. Ninject allows us to solve this problem by creating a module. This class needs to implement INinjectModule. For simplicity, we could also inherit from NinjectModule class.

using Ninject.Modules;
using Prabir.NinjectSample.Provider;
using Prabir.NinjectSamples.Providers.ConsoleWriter;
using Prabir.NinjectSample.Providers.MessageBoxWriter;

namespace Prabir.NinjectSample.ConsoleApplication
{
    public class XDocModule : NinjectModule
    {

        public override void Load()
        {
            Bind<IWriter>().To<ConsoleWriter>();
            Bind<XDoc>().ToSelf().InSingletonScope();
        }

    }
}

Load method is overridden and is the place where magic happens. The above code tell the application that whenever you see IWriter inject ConsoleWriter. Then tell XDoc that service is self-bound and that it should be instantiated only once and has to be reused for other subsequent requests.

Finally in the main program we create a Kernel using the XDocModule we defined.

using Ninject;
using Prabir.NinjectSample.Provider;

namespace Prabir.NinjectSample.ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            IKernel kernel = new StandardKernel(new XDocModule());

            XDoc doc = kernel.Get<XDoc>();

            doc.Writer.Write("Hello from www.prabir.me ");
            doc.Writer.Write(2);
        }
    }
}

Since XDoc was bound as singleton Get<XDoc>() function will return the same instance if called more than once. Then we can call the Writer.Write method to write to console as we defined it in our Module. Incase we want to show a message box rather than console, we would only need to change the Module to

Bind<IWriter>().To<MessageBoxWriter>();

Prabir.NinjectSample.zip (398.25 kb)

[In addition to blogging, I am also now using Twitter for sharing ideas. Follow me at: twitter.com/prabirshrestha]


blog comments powered by Disqus