Be a Dependency Injection Ninja with Ninject

Howdy all,

Firstly, a big old fashioned apology for not being ‘on-the-wire’ much over recent weeks. It’s been an interesting time having accepted an exciting new job, which is amazing; but I’ve also had to contend with a few other sizeable life-boulders off to the side. Nothing I can’t handle, of course, so here I am back with you :-).

I find myself about a third of the way through what I can only express to you as an excellent book (so far); ASP.NET Web API 2: Building a REST Service from Start to Finish. It seems prudent to go over a couple of notable sections that have caught my eye so far. The first topic of conversation is using Ninject for Dependency Injection, which I’ve found to be a solid and compelling alternative to Autofac; the latter I’ve already covered in this post. I’ll follow this up, in a one-two punch style, with a small ASP.NET Web API project showcasing a very cool Namespace HTTP Controller Selector, introduced as a very useful utility class in the book. Best intentions, of course, to produce and roll out these posts as close to one another as possible, so I’ll do my best!

Moving on swiftly, in order to quickly run through the pertinent pieces of the Ninject puzzle, I’ve crafted a very trivial console application that represents a ‘Robot Factory’, painting and outfitting (with weapons) robots that, once deployed, move, speak and attempt to murder one another (being a console application some imagination will be required, ahem!).

Now you know the ‘what’, let’s take a look at the ‘how’ (plus look at Ninjects involvement here as a Dependency Injection solution). We’re basically plugging in the concept of an IoC (Inversion of Control) Container here.

Program Structure

Let’s, to get this ball a-rollin’, have a look at a class diagram outlining our application:

Overview of the Robot Factory Application by Class Diagram.

Robot Factory Application Class Diagram.

Being a console application, the inception point will be the traditional Main method within the Program class:

Program Class

using Ninject;
using Ninject.Modules;
using RobotArmyProcessingLine.DI;
using RobotArmyProcessingLine.Interface;
using System;
using System.Linq;

namespace RobotArmyProcessingLine
{
    /// <summary>
    /// Core RobotArmyProcessingLine Application.
    /// </summary>
    class Program
    {
        #region Private Static IKernel Ninject Container

        /// <summary>
        /// Represents the IKernel Ninject Container
        /// for this RobotArmyProcessingLine Application.
        /// </summary>
        private static IKernel container;

        #endregion Private Static IKernel Ninject Container

        #region Main Application Entry Point

        /// <summary>
        /// RobotArmyProcessingLine Main entry point.
        /// </summary>
        /// <param name="args">Optional input arguments for this application.</param>
        static void Main(string[] args)
        {
            // Configure the Ninject DI Container ready for use (before the application kicks in
            ConfigureNinjectForApplication();

            // Run the application 'proper'
            RunApplication();
        }

        #endregion Main Application Entry Point

        #region Ninject Static Configuration Method

        /// <summary>
        /// Private static helper method that configures the Ninject
        /// Container for use in this test application.
        /// </summary>
        private static void ConfigureNinjectForApplication()
        {
            // Create a StandardKernel object, adding in INinjectModule supporting 
            // objects (all with a load method binding interfaces to concrete types)
            container = new StandardKernel(new INinjectModule[]
            {
                new FactoryModule(),
                new FactoryUtilityModule(),
                new RobotModule()
            });
        }

        #endregion Ninject Static Configuration Methods

        #region Private Static Application Methods

        /// <summary>
        /// Private static helper method that creates a 
        /// 'Factory' and kicks off the process of deploying robots.
        /// </summary>
        private static void RunApplication()
        {
            IRobotFactory robotFactory;

            try
            {
                // Attempt to retrieve a Robot Factory (based in a mapping to the IRobotFactory interface)
                robotFactory = container.TryGet<IRobotFactory>();

                if (robotFactory != null)
                {
                    // We retrieved a valid 'Factory'. Add Robots to the Factory and 'Process' 
                    // and 'Deploy' them if the Factory is not 'oversubscribed' and is therefore functional
                    robotFactory.AddRobots(GetTestRobots());

                    if (robotFactory.FactoryOperational)
                    {
                        PerformFactoryProcessing(robotFactory);
                        DeployRobots(robotFactory);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("An error occurred whilst processing/deploying Robots: Exception Message: " + ex.Message);
            }

            Console.ReadLine();
        }

        /// <summary>
        /// Private static helper test method that generates
        /// a basic list of test Robots.
        /// </summary>
        /// <returns>A List of IRobot supporting objects.</returns>
        private static IRobot[] GetTestRobots()
        {
            return new IRobot[]
            {
                (IRobot)container.TryGet<ISmallRobot>(),
                (IRobot)container.TryGet<ISmallRobot>(),
                (IRobot)container.TryGet<ISmallRobot>(),
                (IRobot)container.TryGet<ISmallRobot>(),
                (IRobot)container.TryGet<ILargeRobot>(),
                (IRobot)container.TryGet<ILargeRobot>(),
                (IRobot)container.TryGet<ILargeRobot>(),
                (IRobot)container.TryGet<ILargeRobot>()
            };
        }

        /// <summary>
        /// Private static helper that triggers a Robot Factories
        /// Paint/AttachWeapons methods (affecting Robots in the Factory).
        /// </summary>
        /// <param name="robotFactory">The Robot Factory to trigger actions on.</param>
        private static void PerformFactoryProcessing(IRobotFactory robotFactory)
        {
            if (robotFactory != null)
            {
                robotFactory.PaintRobots();
                robotFactory.AttachWeapons();
            }
        }

        /// <summary>
        /// Private static helper that triggers a Robot Factories
        /// DeployRobots method (affecting Robots in the Factory).
        /// </summary>
        /// <param name="robotFactory">The Robot Factory to trigger the action on.</param>
        private static void DeployRobots(IRobotFactory robotFactory)
        {
            // If Factory is not null then deploy the Robots
            robotFactory?.DeployRobots().ToList().ForEach(robot =>
            {
                // If each robot is not null then trigger various robot behaviours (move, speak, attack, etc.) and 'output', depending on implementation
                if (robot != null)
                {
                    robot.Move();
                    robot.Speak();
                    robot.Attack();

                    if (robot is ISmallRobot)
                    {
                        ((ISmallRobot)robot).Sneak();
                    }
                    else if (robot is ILargeRobot)
                    {
                        ((ILargeRobot)robot).Crush();
                    }
                }

                Console.WriteLine();
            });
        }

        #endregion Private Static Application Methods
    }
}

To get started, the project in question needs to bring into scope the appropriate Ninject assembly, which can be done via Nuget (either the Package Manager or Package Manager Console):

Ninject Nuget Package via the Nuget Package Manager.

Ninject Nuget Package.

As far as the code goes, there are a few things to discuss here. Much like with Autofac, the concept of a Dependency Injection container is key and takes the form of an IKernel supporting object (we’re using a private, static reference here for demonstration purposes). The container is ‘configured’ within the ConfigureNinjectForApplication method using a set of module based classes. In short, these modules are used, keeping logical grouping at the very fore of the thought process here, to bind interfaces to concrete types; that’s basically it. We’ll see these modules fully fleshed out later, but notice how we can pass an array of modules to the StandardKernel constructor, which causes every single module’s Load method to be called, binding ‘services’ to ‘implementations’.

After the very high-level Ninject configuration step the RunApplication method is triggered, which gets the configured implementation (based on module setup) of IRobotFactory using the TryGet method on the container, which returns null if a ‘mapped’ type cannot be found (a Ninject container supports a Get method also, but I’ve opted for a TryGet here, meaning no exception is raised in this scenario if a mapping cannot be found between the interface specified and a concrete type).

Once we have the robot factory we add some test robots to it with the aid of the GetTestRobots method, using the container to get an array of IRobot supporting types. The list technically contains small and large robots, which implement different interfaces actually; more on this later.

Factories can paint and arm robots, and this functionality on the factory is triggered by the PerformFactoryProcessing method. The way in which robots are painted and armed is cleverly handled by Dependency Injection, based on mappings between the IPainter/IWeaponAttacher interfaces and concrete types (again by custom classes inheriting from NinjectModule).

Finally, robots are deployed for combat and move, speak, attack and perform interface specific actions, just for kicks more than anything! The way in which robots ‘output’ their various actions is also tied to a little sprinkling of DI; I’ll discuss this as we move forward.

Ninject Dependency Injection Module Configuration

As you saw earlier a little bit of magic occurs within the Program class and the ConfigureNinjectForApplication method. A StandardKernel type is created here, passing in an array of INinjectModule supporting types. These modules, as mentioned before, just contain logical groupings of mappings between interfaces and concrete types. When a container is asked to ‘resolve’ (in Autofac speak) or ‘get’ instances based on an interface, the mapped concrete type is returned; simples! Time for a wee squiz at our custom modules, which all inherit from the NinjectModule type:

using Ninject.Modules;
using RobotArmyProcessingLine.Interface;
using RobotArmyProcessingLine.Production;

namespace RobotArmyProcessingLine.DI
{
    /// <summary>
    /// Denotes a Ninject Factory Module 
    /// determining the mappings between Robot 
    /// Factory Interfaces and associated Concrete Types.
    /// </summary>
    public class FactoryModule : NinjectModule
    {
        #region Overridden Load Method

        /// <summary>
        /// Overridden Load method to bind services
        /// to concrete types.
        /// </summary>
        public override void Load()
        {
            // Bind IRobotFactory to a concrete type (in this case, as a singleton - i.e. same instance return when the container
            // is asked to 'get' an instance based on the interface)
            Bind<IRobotFactory>().To<LargeRobotFactory>().InSingletonScope();
        }

        #endregion Overridden Load Method
    }
}

.....

using Ninject.Modules;
using RobotArmyProcessingLine.Interface;
using RobotArmyProcessingLine.Model;

namespace RobotArmyProcessingLine.DI
{
    /// <summary>
    /// Denotes a Ninject Factory Utility Module 
    /// determining the mappings between Robot 
    /// Factory Utility Interfaces and associated Concrete Types. 
    /// </summary>
    public class FactoryUtilityModule : NinjectModule
    {
        #region Overridden Load Method

        /// <summary>
        /// Overridden Load method to bind services
        /// to concrete types.
        /// </summary>
        public override void Load()
        {
            // A 'Factory' is able to paint robots and attach weapons. Map services (interfaces) to concrete
            // types for when a 'get' on the Ninject IoC container is used
            Bind<IPainter>().To<BlueWaterPaintMachine>().InSingletonScope();
            Bind<IWeaponAttacher>().To<RocketLauncherAttacher>().InSingletonScope();
        }

        #endregion Overridden Load Method
    }
}

.....

using Ninject.Modules;
using RobotArmyProcessingLine.Interface;
using RobotArmyProcessingLine.Model;

namespace RobotArmyProcessingLine.DI
{
    /// <summary>
    /// Denotes a Ninject Robot Module 
    /// determining the mappings between Robot 
    /// Interfaces and associated Concrete Types. 
    /// </summary>
    public class RobotModule : NinjectModule
    {
        #region Overridden Load Method

        /// <summary>
        /// Overridden Load method to bind services
        /// to concrete types.
        /// </summary>
        public override void Load()
        {
            // Determine the concrete types associated with ISmallRobot and ILargeRobot
            Bind<ISmallRobot>().To<SmallRobotV1>();
            Bind<ILargeRobot>().To<LargeRobotV1>();

            // Something a bit different here. We bind slightly different concrete types to IRobotOutputter based on
            // the type it is being 'injected' into (determines how robots output information about commands they undertake)
            Bind<IRobotOutputter>().To<RobotOutput>().WhenInjectedInto<ISmallRobot>().InSingletonScope();
            Bind<IRobotOutputter>().To<RobotFileOutput>().WhenInjectedInto<ILargeRobot>().InSingletonScope();
        }

        #endregion Overridden Load Method
    }
}

These custom module class types are hopefully pretty terse. All modules override the base class Load method and are where the logic is housed to bind interfaces to implementations, nothing more and nothing less. I’ve split the mappings for the factory and the factory constructor arguments into two separate modules, just for a clean separation, although I have to admit I would need to do some further reading up to reveal the truth behind best practice here.

Ninject employs a ‘fluent’ declarative style, using chained method calls to determine the various facets of how an interface is mapped to a concrete type, for example (or control the specifics on how a concrete instance is returned). By default, types are returned in a ‘transient’ nature; meaning you get a new instance of a type each and every time a get operation is performed using the container. However, you can probably spot that I have used the InSingletonScope method that will force a single instance of a type to be created and returned constantly when requested from the container.

The RobotModule type has a little extra trickery going in in relation to how requests for IRobotOutputter implementing objects are handled when requested from the container. Ninject enables you to return a different concrete implementation, when an interface type is requested, depending on the type it is being injected into (i.e. via constructor injection, for example). Here, a request for an IRobotOutputter implementing type will result in either a RobotOutput or RobotFileOutput type, depending on whether it is being passed into a small or large robot, respectively. This is so very, very cool!

To summarize, create the custom modules you require (deriving from NinjectModule and overriding the Load method) and bind interfaces to concrete types, always keeping in mind if you need singletons or new instances when requests are made from the container. Then, consider if you need further control over how types are bound and returned, depending on the interplay between types (i.e. what are they being injected into for example). You should then be in pretty good shape.

I have found the Ninject help documentation to be fairly good in pointing out the nuances of how this works and options available to you; I’ll include a link at the end of this blog post for further perusal (you can actually handle service/implementation hooking up via an XML mapping file, if you choose, so read up!) ;-).

We’ve seen what the core program class does and how our Ninject DI container is configured using modules/interface and type mappings. Now, strut your way on to seeing the interfaces and types relating to factories and robots.

The Robot Factory

Factories!!! The core backbone of our robot making world! They paint, arm and deploy our robots.

I’ve done my best here to adhere to the ‘D’ of the SOLID design principles; Dependency Inversion (which is a different concept to Dependency Injection, and should not be confused). In order to paint and attach weapons to robots, factories rely on the IPainter and IWeaponAttacher abstractions only, and no actual concrete types (decoupling this class so that it does not have fixed dependency on a specific concrete type). Ninject, on the flip-side, handles the Dependency Injection process for us and passes in appropriate types for us when a factory is created, based on module mappings discussed earlier on.

There is an IRobotFactory interface for starters, defining common factory behaviours as follows:

using System.Collections.Generic;

namespace RobotArmyProcessingLine.Interface
{
    /// <summary>
    /// Core interface describing shared behaviours
    /// for a 'Factory' in this application.
    /// </summary>
    public interface IRobotFactory
    {
        #region Interface Properties

        /// <summary>
        /// Interface property that can be implemented
        /// to control the specifics behind 
        /// whether a 'Factory’ is operational or not.
        /// </summary>
        bool FactoryOperational { get; }

        #endregion Interface Properties

        #region Interface Methods

        /// <summary>
        /// Interface method that can be implemented to kick
        /// off a Factories ability to Paint Robots.
        /// See <seealso cref="IPainter"/> and 
        /// <seealso cref="IRobot"/> for linked behaviour objects.
        /// </summary>
        void PaintRobots();

        /// <summary>
        /// Interface method that can be implemented to kick
        /// off a Factories ability to arm Robots.
        /// See <seealso cref="IWeaponAttacher"/> and 
        /// <seealso cref="IRobot"/> for linked behaviour objects.
        /// </summary>
        void AttachWeapons();

        /// <summary>
        /// Interface method that can be implemented to control
        /// how <see cref="IRobot"/> based objects are added
        /// to a particular Factories production line.
        /// </summary>
        /// <param name="robotsToAdd">An array (params or set array) of <see cref="IRobot"/> implementing objects to add to the Factory production line.</param>
        void AddRobots(params IRobot[] robotsToAdd);

        /// <summary>
        /// Interface method that can be implemented to control
        /// how <see cref="IRobot"/> objects, within a factory, are
        /// deployed back to the front lines (aka, the method caller).
        /// </summary>
        /// <returns>An <see cref="IList{T}"/> of <see cref="IRobot"/> based objects.</returns>
        IList<IRobot> DeployRobots();

        #endregion Interface Methods
    }
}

Fairly basic stuff; factories paint, arm and deploy robots. Robots can be added to a factories production line using the AddRobots method (only the abstraction of IRobot is used here). All factories have a mechanism for returning a boolean stating if the factory is operational (which I didn’t fully tie into the final implementations, so definite scope for improvement here).

A RobotFactory abstract base class models what a basic factory looks like, using IRobotFactory:

using RobotArmyProcessingLine.Interface;
using System.Collections.Generic;
using System.Linq;

namespace RobotArmyProcessingLine.Production
{
    /// <summary>
    /// Base class defining shared elements for all robot factories.
    /// Provides abstract members and <see cref="IRobotFactory"/> based members.
    /// </summary>
    public abstract class RobotFactory : IRobotFactory
    {
        #region Private Fields

        /// <summary>
        /// An <see cref="IPainter"/> based object for painting robots in the factory.
        /// </summary>
        private IPainter paintMachine;

        /// <summary>
        /// An <see cref="IWeaponAttacher"/> based object for arming robots in the factory.
        /// </summary>
        private IWeaponAttacher weaponAttacherMachine;

        #endregion Private Fields

        #region Protected (Get) Properties

        /// <summary>
        /// Allow a factory access to the robots (<see 
        /// cref="IRobot"/> types) in the production line.
        /// </summary>
        protected List<IRobot> Robots { get; private set; }

        #endregion Protected (Get) Properties

        #region Public Abstract Properties

        /// <summary>
        /// public abstract member that needs to be implemented by
        /// deriving factories to determine the conditions under which
        /// the factory is operational (i.e. the production line is not overloaded).
        /// </summary>
        public abstract bool FactoryOperational { get; }

        #endregion Public Abstract Properties

        #region Constructor

        /// <summary>
        /// Constructor for a RobotFactory that sets
        /// the <see cref="IPainter"/> and <see cref="IWeaponAttacher"/> implementing
        /// objects on this type (all factories can paint/arm robots).
        /// </summary>
        /// <param name="paintMachineToUse">An <see cref="IPainter"/> implementing object for this factory to paint robots.</param>
        /// <param name="weaponAttacherMachineToUse">An <see cref="IWeaponAttacher"/> implementing object for this factory to arm robots.</param>
        public RobotFactory(IPainter paintMachineToUse, IWeaponAttacher weaponAttacherMachineToUse)
        {
            Robots = new List<IRobot>();
            paintMachine = paintMachineToUse;
            weaponAttacherMachine = weaponAttacherMachineToUse;
        }

        #endregion Constructor

        #region IRobotFactory Interface Methods

        /// <summary>
        /// public method that paints robots on the production line.
        /// </summary>
        public void PaintRobots()
        {
            Robots?.ForEach(robot =>
            {
                paintMachine.Paint(robot);
            });
        }

        /// <summary>
        /// public method that attaches weapons to robots on the production line. 
        /// </summary>
        public void AttachWeapons()
        {
            Robots?.ForEach(robot =>
            {
                weaponAttacherMachine.AttachWeapons(robot);
            });
        }

        /// <summary>
        /// public method that adds robots (<see cref="IRobot"/> objects) on to the production line. 
        /// </summary>
        /// <param name="robotsToAdd">An array of type <see cref="IRobot"/> defining the robots to add to the production line.</param>
        public void AddRobots(params IRobot[] robotsToAdd)
        {
            if (robotsToAdd?.Count() > 0)
            {
                Robots.AddRange(robotsToAdd);
            }
        }

        /// <summary>
        /// public method that deploys robots off the production line.
        /// Clears down the production line in the factory and returns all robots to the caller.
        /// </summary>
        /// <returns>Returns an <see cref="IList{T}"/> of <see cref="IRobot"/> types.</returns>
        public IList<IRobot> DeployRobots()
        {
            // Copy robots to a new IList - Ready for deployment
            IList<IRobot> robotsToDeploy = new List<IRobot>(Robots);

            // Clear the current production line
            Robots.Clear();

            // Deploy!
            return robotsToDeploy;
        }

        #endregion IRobotFactory Interface Methods
    }
}

You’ll see the small and large factories in a second, which really just allow me to determine different conditions for a factory being ‘operational’. As for the abstract base class outlined here; when trying to properly decouple types from each other and keep interactions between types based purely on abstractions, a common approach you will come across is pushing all dependencies ‘up’ to the constructor. The constructor can then be geared to accept interface types and references can then simply be stored for use within the class (see the private IPainter and IWeaponAttacher fields). We are freed from the need to ‘new-up’ instances of types within the body of methods in this class, which would instantly introduce coupling and unrequired dependencies. The methods for painting, arming and adding robots are fairly self-explanatory (notice the standard use of containment-delegation mechanics here to just ‘delegate’ on calls for painting/arming robots to the IPainter and IWeaponAttacher objects, without this type needing to use/know about concrete implementations), I’ll leave you to mull over these. When robots are deployed, they leave the ‘production line’ queue and are returned to the caller for use in the ‘field’; there is a fantastic robot war going on in my mind anyway!

For completeness, here are the implementations for the small and large robot factories, both deriving from the RobotFactory type (we use constructor chaining here to pass the IPainter and IWeaponAttacher types up to the base class, and override the FactoryOperational property; that being about it!):

using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Production
{
    /// <summary>
    /// Type that defines a 'large' factory that can process
    /// (paint, arm and deploy) <see cref="IRobot"/> implementing objects.
    /// Utilises <seealso cref="IPainter"/> and <seealso cref="IWeaponAttacher"/> utility classes.
    /// </summary>
    public class LargeRobotFactory : RobotFactory
    {
        #region Public Overridden Properties

        /// <summary>
        /// public overridden property that determines if this
        /// factory is operational. This factory is not operational
        /// if the production line (robot count) exceeds the maximum limit
        /// (we could of course add additional logic in here for this factory type).
        /// </summary>
        public override bool FactoryOperational
        {
            get
            {
                return Robots?.Count <= 20;
            }
        }

        #endregion Public Overridden Properties

        #region Constructor

        /// <summary>
        /// Constructor for a LargeRobotFactory that passes
        /// the <see cref="IPainter"/> and <see cref="IWeaponAttacher"/> implementing
        /// object to the base class (all factories can paint/arm robots).
        /// </summary>
        /// <param name="paintMachineToUse">An <see cref="IPainter"/> implementing object for this factory to paint robots.</param>
        /// <param name="weaponAttacherMachineToUse">An <see cref="IWeaponAttacher"/> implementing object for this factory to arm robots.</param>
        public LargeRobotFactory(IPainter paintMachineToUse, IWeaponAttacher weaponAttacherMachineToUse)
            : base(paintMachineToUse, weaponAttacherMachineToUse)
        {

        }

        #endregion Constructor
    }
}

.....

using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Production
{
    /// <summary>
    /// Type that defines a 'small' factory that can process
    /// (paint, arm and deploy) <see cref="IRobot"/> implementing objects.
    /// Utilises <seealso cref="IPainter"/> and <seealso cref="IWeaponAttacher"/> utility classes.
    /// </summary>
    public class SmallRobotFactory : RobotFactory
    {
        #region Public Overridden Properties

        /// <summary>
        /// public overridden property that determines if this
        /// factory is operational. This factory is not operational
        /// if the production line (robot count) exceeds the maximum limit
        /// (we could of course add additional logic in here for this factory type).
        /// </summary>
        public override bool FactoryOperational
        {
            get
            {
                return Robots?.Count <= 10;
            }
        }

        #endregion Public Overridden Properties

        #region Constructor

        /// <summary>
        /// Constructor for a SmallRobotFactory that passes
        /// the <see cref="IPainter"/> and <see cref="IWeaponAttacher"/> implementing
        /// object to the base class (all factories can paint/arm robots).
        /// </summary>
        /// <param name="paintMachineToUse">An <see cref="IPainter"/> implementing object for this factory to paint robots.</param>
        /// <param name="weaponAttacherMachineToUse">An <see cref="IWeaponAttacher"/> implementing object for this factory to arm robots.</param>
        public SmallRobotFactory(IPainter paintMachineToUse, IWeaponAttacher weaponAttacherMachineToUse)
            : base(paintMachineToUse, weaponAttacherMachineToUse)
        {

        }

        #endregion Constructor
    }
}

If you’re interested, here are the IPainter and IWeaponAttacher interface definitions, along with concrete implementations (that you’ll see being mapped within the FactoryUtilityModule Ninject configuration class):

namespace RobotArmyProcessingLine.Interface
{
    /// <summary>
    /// Interface describing behaviours
    /// for a Painting Machine that can operate 
    /// against an <see cref="IRobot"/> implementing object.
    /// </summary>
    public interface IPainter
    {
        #region Interface Methods

        /// <summary>
        /// Interface method that can be implemented
        /// to 'Paint' an <see cref="IRobot"/> implementing object.
        /// </summary>
        /// <param name="robot">The <see cref="IRobot"/> implementing type to paint.</param>
        void Paint(IRobot robot);

        #endregion Interface Methods
    }
}

.....

namespace RobotArmyProcessingLine.Interface
{
    /// <summary>
    /// Interface describing behaviours
    /// for a Weapon Attachment Machine that can operate 
    /// against an <see cref="IRobot"/> implementing object.
    /// </summary>
    public interface IWeaponAttacher
    {
        #region Interface Methods

        /// <summary>
        /// Interface method that can be implemented
        /// to 'attach weapons' to an <see cref="IRobot"/> implementing object.
        /// </summary>
        /// <param name="robot">The <see cref="IRobot"/> implementing type to attach weapons to.</param>
        void AttachWeapons(IRobot robot);

        #endregion Interface Methods
    }
}

.....

using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Defines a type that can be used to paint <see cref="IRobot"/>
    /// objects with blue, water-based paint.
    /// </summary>
    public class BlueWaterPaintMachine : IPainter
    {
        #region Private Constants

        /// <summary>
        /// Private constant that holds a description of how this paint
        /// machine will paint a given robot.
        /// </summary>
        private const string paintDescription = "painted in blue, water-based paint";

        #endregion Private Constants

        #region Public IPainter Interface Methods

        /// <summary>
        /// Public method that paints the passed in 
        /// <see cref="IRobot"/> object.
        /// </summary>
        /// <param name="robot">The <see cref="IRobot"/> to be painted (if it's not null).</param>
        public void Paint(IRobot robot)
        {
            // If the robot is not null then paint it
            robot?.Paint(paintDescription);
        }

        #endregion Public IPainter Interface Methods
    }
}

.....

using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Defines a type that can be used to paint <see cref="IRobot"/>
    /// objects with red, lead-based paint.
    /// </summary>
    public class RedLeadPaintMachine : IPainter
    {
        #region Private Constant

        /// <summary>
        /// Private constant that holds a description of how this paint
        /// machine will paint a given robot.
        /// </summary>
        private const string paintDescription = "painted in red, lead-based paint";

        #endregion Private Constant

        /// <summary>
        /// Public method that paints the passed in 
        /// <see cref="IRobot"/> object.
        /// </summary>
        /// <param name="robot">The <see cref="IRobot"/> to be painted (if it's not null).</param>
        public void Paint(IRobot robot)
        {
            // If the robot is not null then paint it
            robot?.Paint(paintDescription);
        }
    }
}

.....

using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Defines a type that can be used to arm <see cref="IRobot"/>
    /// objects with a minigun.
    /// </summary>
    public class MinigunAttacher : IWeaponAttacher
    {
        #region Private Constants

        /// <summary>
        /// Private constant that holds a description of how this weapon
        /// attachment machine will arm a given robot.
        /// </summary>
        private const string weaponDescription = "minigun attachment!";

        #endregion Private Constants

        #region Public IWeaponAttacher Interface Methods

        /// <summary>
        /// Public method that arms the passed in 
        /// <see cref="IRobot"/> object.
        /// </summary>
        /// <param name="robot">The <see cref="IRobot"/> to be armed (if it's not null).</param>
        public void AttachWeapons(IRobot robot)
        {
            robot?.AttachWeapons(weaponDescription);
        }

        #endregion Public IWeaponAttacher Interface Methods
    }
}

.....

using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Defines a type that can be used to arm <see cref="IRobot"/>
    /// objects with a rocket launcher.
    /// </summary>
    public class RocketLauncherAttacher : IWeaponAttacher
    {
        #region Private Constants

        /// <summary>
        /// Private constant that holds a description of how this weapon
        /// attachment machine will arm a given robot.
        /// </summary>
        private const string weaponDescription = "rocket launcher attachment!";

        #endregion Private Constants

        #region Public IWeaponAttacher Interface Methods

        /// <summary>
        /// Public method that arms the passed in 
        /// <see cref="IRobot"/> object.
        /// </summary>
        /// <param name="robot">The <see cref="IRobot"/> to be armed (if it's not null).</param>
        public void AttachWeapons(IRobot robot)
        {
            robot?.AttachWeapons(weaponDescription);
        }

        #endregion Public IWeaponAttacher Interface Methods
    }
}

That’s the factories all set and ready to rock and roll! So, what about the robots you ask? On to that next :-).

The Robots

Much like the factories, robots utilise an IRobot interface that a base class implements to give us a feel for standard behaviours that all robots share:

namespace RobotArmyProcessingLine.Interface
{
    /// <summary>
    /// Core interface describing shared behaviours
    /// for a 'Robot' in this application.
    /// </summary>
    public interface IRobot
    {
        #region Interface Properties

        /// <summary>
        /// Interface property that describes
        /// a robots paint job.
        /// </summary>
        string PaintDescription { get; }

        /// <summary>
        /// Interface property that describes
        /// a robots weapon attachment.
        /// </summary>
        string WeaponDescription { get; }

        #endregion Interface Properties

        #region Interface Methods

        /// <summary>
        /// Interface method that, when 
        /// implemented, 'moves' a robot.
        /// </summary>
        void Move();

        /// <summary>
        /// Interface method that, when 
        /// implemented, makes a robot 'speak'.
        /// </summary>
        void Speak();

        /// <summary>
        /// Interface method that, when 
        /// implemented, makes a robot 'speak'.
        /// </summary>
        void Attack();

        /// <summary>
        /// Interface method that, when implemented, controls
        /// the specifics of how a robot is painted. This ties 
        /// to an<seealso cref="IPainter"/> implementing 
        /// object (of an <seealso cref="IRobotFactory" /> object).
        /// </summary>
        /// <param name="robotPaintDescription">A string that provides details on the robot paint job.</param>
        void Paint(string robotPaintDescription);

        /// <summary>
        /// Interface method that, when implemented, controls
        /// the specifics of how a robot receives weapon attachments.
        /// This ties to an <seealso cref="IWeaponAttacher"/> 
        /// implementing object (of an <seealso cref="IRobotFactory" /> object).
        /// </summary>
        /// <param name="robotWeaponAttachmentDescription">A string that provides details on the robots weapon attachments.</param>
        void AttachWeapons(string robotWeaponAttachmentDescription);

        #endregion Interface Methods
    }
}

As we’ve mentioned a few times now (hopefully I haven’t sent you to sleep by stating the same bloody stuff over and over again!) robots can move, speak and attack. They also have properties that denote how they have been painted and armed, along with methods that allow the paint and armament descriptions to be set for each robot. Again, a pretty egg-suck style interface this one.

Time for the Robot abstract base class then:

using System;
using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Provides an abstract, base definition for all robots
    /// in this application, utlising the <see cref="IRobot"/> interface.
    /// </summary>
    public abstract class Robot : IRobot
    {
        #region Protected (Get) Properties

        /// <summary>
        /// The <see cref="IRobotOutputter"/> implementing object that can
        /// be used to determine how this robot outputs messages.
        /// </summary>
        protected IRobotOutputter MessageOutputter { get; private set; }

        #endregion Protected Properties

        #region Public (Get) Properties

        /// <summary>
        /// The description of the paint job applied to this robot
        /// after it has been through the factory production line (or some other process).
        /// </summary>
        public string PaintDescription { get; private set; }

        /// <summary>
        /// The description of the weapon attachments applied to this robot
        /// after it has been through the factory production line (or some other process).
        /// </summary>
        public string WeaponDescription { get; private set; }

        #endregion Public (Get) Properties

        #region Constructor

        /// <summary>
        /// Constructor for this base class that consumes and sets
        /// this types <see cref="IRobotOutputter"/> object for
        /// handling how a robot pushes out messages.
        /// </summary>
        /// <param name="outputter">The <see cref="IRobotOutputter"/> object for the robot to use for messaging.</param>
        public Robot(IRobotOutputter outputter)
        {
            // Robots must be able to output, no exceptions (i.e. throw an exception! Probably bad comment wording ahem)
            if (outputter == null)
            {
                throw new ArgumentNullException(nameof(outputter));
            }

            MessageOutputter = outputter;
        }

        #endregion Constructor

        #region Public Abstract IRobot Interface Methods

        /// <summary>
        /// Public abstract method that must be overridden by
        /// deriving types to determine how a robot attacks.
        /// </summary>
        public abstract void Attack();

        /// <summary>
        /// Public abstract method that must be overridden by
        /// deriving types to determine how a robot moves.
        /// </summary>
        public abstract void Move();

        /// <summary>
        /// Public abstract method that must be overridden by
        /// deriving types to determine how a robot speaks.
        /// </summary>
        public abstract void Speak();

        #endregion public abstract IRobot Interface Methods

        #region Public IRobot Interface Methods

        /// <summary>
        /// Public method that is used to pass details
        /// of a paint job to this robot.
        /// </summary>
        /// <param name="robotPaintDescription">The paint job applied to the robot.</param>
        public void Paint(string robotPaintDescription)
        {
            PaintDescription = robotPaintDescription;
        }

        /// <summary>
        /// Public method that that is used to pass details
        /// of the weapon that is to be used by this robot.
        /// </summary>
        /// <param name="robotWeaponAttachmentDescription">The weapon added to the robot.</param>
        public void AttachWeapons(string robotWeaponAttachmentDescription)
        {
            WeaponDescription = robotWeaponAttachmentDescription;
        }

        #endregion Public IRobot Interface Methods
    }
}

Bit by bit then…

We’ve implemented the Paint and AttachWeapons methods at this level, which just sets the paint job and armament description for this robot, easy peasy. The Attack, Move and Speak methods are fully abstract here and I’ll be forcing derived class types to implement these (small/large robots are going to perform these actions differently). Again, dependencies have been ‘pushed’ to the constructor. All robots ‘output’ their actions using an IRobotOutputter implementing type; this is me going abstraction crazy for demonstration purposes, and sticking to the Dependency Inversion principle as closely as I can of course!

Robot derived implementations will be using this IRobotOutputter type, as you can see here (small and large robots are ‘versioned’, although that doesn’t really play a massive part in this iteration of the application; if you are following along you could swap out V1 for V2 variants in the appropriate Ninject module mapping class just to prove a point):

using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Provides the definition for a Version 1, 'Small Robot'.
    /// </summary>
    public sealed class SmallRobotV1 : Robot, ISmallRobot
    {
        #region Constructor

        /// <summary>
        /// Constructor for a SmallRobotV1, which passes
        /// a <see cref="IRobotOutputter"/> object to the 
        /// <seealso cref="Robot"/> base class for future use.
        /// </summary>
        /// <param name="outputter">The <see cref="IRobotOutputter"/> object to determine how this robot outputs command details.</param>
        public SmallRobotV1(IRobotOutputter outputter)
            : base(outputter)
        {

        }

        #endregion Constructor

        #region IRobot Interface Methods

        /// <summary>
        /// Public method that makes this robot attack.
        /// </summary>
        public override void Attack()
        {
            MessageOutputter.WriteLine($"SmallRobotV1 { PaintDescription ?? string.Empty } attacking with a { WeaponDescription ?? string.Empty }!");
        }

        /// <summary>
        /// Public method that makes this robot move.
        /// </summary>
        public override void Move()
        {
            MessageOutputter.WriteLine($"SmallRobotV1 { PaintDescription ?? string.Empty } moving!");
        }

        /// <summary>
        /// Public method that makes this robot speak.
        /// </summary>
        public override void Speak()
        {
            MessageOutputter.WriteLine($"SmallRobotV1 { PaintDescription ?? string.Empty } speaking!");
        }

        #endregion IRobot Interface Methods

        #region ISmallRobot Interface Methods

        /// <summary>
        /// Public method that makes this robot sneak.
        /// </summary>
        public void Sneak()
        {
            MessageOutputter.WriteLine($"SmallRobotV1 { PaintDescription ?? string.Empty } sneaking!");
        }

        #endregion ISmallRobot Interface Methods
    }
}

.....

using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Provides the definition for a Version 2, 'Small Robot'.
    /// </summary>
    public sealed class SmallRobotV2 : Robot, ISmallRobot
    {
        #region Constructor

        /// <summary>
        /// Constructor for a SmallRobotV2, which passes
        /// a <see cref="IRobotOutputter"/> object to the 
        /// <seealso cref="Robot"/> base class for future use.
        /// </summary>
        /// <param name="outputter">The <see cref="IRobotOutputter"/> object to determine how this robot outputs command details.</param>
        public SmallRobotV2(IRobotOutputter outputter)
            : base(outputter)
        {

        }

        #endregion Constructor

        #region IRobot Interface Methods

        /// <summary>
        /// Public method that makes this robot attack.
        /// </summary>
        public override void Attack()
        {
            MessageOutputter.WriteLine($"SmallRobotV2 { PaintDescription ?? string.Empty } attacking with a { WeaponDescription ?? string.Empty }!");
        }

        /// <summary>
        /// Public method that makes this robot move.
        /// </summary>
        public override void Move()
        {
            MessageOutputter.WriteLine($"SmallRobotV2 { PaintDescription ?? string.Empty } moving!");
        }

        /// <summary>
        /// Public method that makes this robot speak.
        /// </summary>
        public override void Speak()
        {
            MessageOutputter.WriteLine($"SmallRobotV2 { PaintDescription ?? string.Empty } speaking!");
        }

        #endregion IRobot Interface Methods

        #region ISmallRobot Interface Methods

        /// <summary>
        /// Public method that makes this robot sneak.
        /// </summary>
        public void Sneak()
        {
            MessageOutputter.WriteLine($"SmallRobotV2 { PaintDescription ?? string.Empty } sneaking!");
        }

        #endregion ISmallRobot Interface Methods
    }
}

.....

using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Provides the definition for a Version 1, 'Large Robot'.
    /// </summary>
    public sealed class LargeRobotV1 : Robot, ILargeRobot
    {
        #region Constructor

        /// <summary>
        /// Constructor for a LargeRobotV1, which passes
        /// a <see cref="IRobotOutputter"/> object to the 
        /// <seealso cref="Robot"/> base class for future use.
        /// </summary>
        /// <param name="outputter">The <see cref="IRobotOutputter"/> object to determine how this robot outputs command details.</param>
        public LargeRobotV1(IRobotOutputter outputter)
            : base(outputter)
        {

        }

        #endregion Constructor

        #region IRobot Interface Methods

        /// <summary>
        /// Public method that makes this robot attack.
        /// </summary>
        public override void Attack()
        {
            MessageOutputter.WriteLine($"LargeRobotV1 { PaintDescription ?? string.Empty } attacking with a { WeaponDescription ?? string.Empty }!");
        }

        /// <summary>
        /// Public method that makes this robot move.
        /// </summary>
        public override void Move()
        {
            MessageOutputter.WriteLine($"LargeRobotV1 { PaintDescription ?? string.Empty } moving!");
        }

        /// <summary>
        /// Public method that makes this robot speak.
        /// </summary>
        public override void Speak()
        {
            MessageOutputter.WriteLine($"LargeRobotV1 { PaintDescription ?? string.Empty } speaking!");
        }

        #endregion IRobot Interface Methods

        #region ILargeRobot Interface Methods

        /// <summary>
        /// Public method that makes this robot crush.
        /// </summary>
        public void Crush()
        {
            MessageOutputter.WriteLine($"LargeRobotV1 { PaintDescription ?? string.Empty } crushing!");
        }

        #endregion ILargeRobot Interface Methods
    }
}

.....

using RobotArmyProcessingLine.Interface;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Provides the definition for a Version 2, 'Large Robot'.
    /// </summary>
    public sealed class LargeRobotV2 : Robot, ILargeRobot
    {
        #region Constructor

        /// <summary>
        /// Constructor for a LargeRobotV2, which passes
        /// a <see cref="IRobotOutputter"/> object to the 
        /// <seealso cref="Robot"/> base class for future use.
        /// </summary>
        /// <param name="outputter">The <see cref="IRobotOutputter"/> object to determine how this robot outputs command details.</param>
        public LargeRobotV2(IRobotOutputter outputter)
            : base(outputter)
        {

        }

        #endregion Constructor

        #region IRobot Interface Methods

        /// <summary>
        /// Public method that makes this robot attack.
        /// </summary>
        public override void Attack()
        {
            MessageOutputter.WriteLine($"LargeRobotV2 { PaintDescription ?? string.Empty } attacking with a { WeaponDescription ?? string.Empty }!");
        }

        /// <summary>
        /// Public method that makes this robot move.
        /// </summary>
        public override void Move()
        {
            MessageOutputter.WriteLine($"LargeRobotV2 { PaintDescription ?? string.Empty } moving!");
        }

        /// <summary>
        /// Public method that makes this robot speak.
        /// </summary>
        public override void Speak()
        {
            MessageOutputter.WriteLine($"LargeRobotV2 { PaintDescription ?? string.Empty } speaking!");
        }

        #endregion IRobot Interface Methods

        #region ILargeRobot Interface Methods

        /// <summary>
        /// Public method that makes this robot crush.
        /// </summary>
        public void Crush()
        {
            MessageOutputter.WriteLine($"LargeRobotV2 { PaintDescription ?? string.Empty } crushing!");
        }

        #endregion ILargeRobot Interface Methods
    }
}

.....

namespace RobotArmyProcessingLine.Interface
{
    /// <summary>
    /// Interface describing additional behaviours
    /// for a 'Large' Robot.
    /// </summary>
    public interface ILargeRobot
    {
        #region Interface Methods

        /// <summary>
        /// Interface method that can be implemented
        /// to perform a 'crush' action.
        /// </summary>
        void Crush();

        #endregion Interface Methods
    }
}

.....

namespace RobotArmyProcessingLine.Interface
{
    /// <summary>
    /// Interface describing additional behaviours
    /// for a 'Small' Robot.
    /// </summary>
    public interface ISmallRobot
    {
        #region Interface Methods

        /// <summary>
        /// Interface method that can be implemented
        /// to perform a 'sneak' action.
        /// </summary>
        void Sneak();

        #endregion Interface Methods
    }
}

It’s kinda noddy right! Hopefully, it proves the point and is enough to demonstrate the mechanics at work later down the line, when the application is run. All robots use the base class MessageOutputter property (which will be a singleton instance of an IRobotOutputter supporting type, based on the RobotModule configuration class we saw earlier) to push out information to a particular output channel. The constructor, much like the factory, is just pushing a dependency up to the base class. Notice the use of the ISmallRobot and ILargeRobot interface types; these are used to denote slight differences in behaviour between robots. Small robots can sneak and large robots crush.

Lastly, before we see the application running, I want to focus on how robots handle their output. Robots again use an abstraction, the IRobotOutputter interface, to handle this. This means the specifics of how output is performed is not tied into the Robot class at all:

namespace RobotArmyProcessingLine.Interface
{
    /// <summary>
    /// Interface describing behaviours
    /// for a Robot Output Module (so that a Robot
    /// can provide details via a designated IO channel
    /// on its various actions (e.g. movement, attacking, etc.).
    /// This is currently utilised by <seealso cref="IRobot"/> implementing objects.
    /// </summary>
    public interface IRobotOutputter
    {
        #region Interface Methods

        /// <summary>
        /// Interface method that can be implemented to control
        /// how (i.e. to what IO Channel, for example) an object publishes messages.
        /// </summary>
        /// <param name="outputMessage"></param>
        void WriteLine(string outputMessage);

        #endregion Interface Methods
    }
}

The implementations control how the WriteLine method actually works. In this sample application, I’ve gone with one type that writes output to the console and another that pushes information to a file, as follows:

using RobotArmyProcessingLine.Interface;
using System;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Type that is used to define an IO (console-based) output
    /// method as a robot messaging output.
    /// </summary>
    public class RobotOutput : IRobotOutputter
    {
        #region IRobotOutputter Interface Methods

        /// <summary>
        /// Allows a message to be output to the console.
        /// See <see cref="IRobot"/> implementing classes for usage.
        /// </summary>
        /// <param name="outputMessage">The message to process.</param>
        public void WriteLine(string outputMessage)
        {
            Console.WriteLine(outputMessage);
        }

        #endregion IRobotOutputter Interface Methods
    }
}

.....

using RobotArmyProcessingLine.Interface;
using System;
using System.IO;

namespace RobotArmyProcessingLine.Model
{
    /// <summary>
    /// Type that is used to define an IO (file-based) output
    /// method as a robot messaging output.
    /// </summary>
    public class RobotFileOutput : IRobotOutputter
    {
        #region IRobotOutputter Interface Methods

        /// <summary>
        /// Allows a message to be output to a file.
        /// See <see cref="IRobot"/> implementing classes for usage.
        /// </summary>
        /// <param name="outputMessage">The message to process.</param>
        public void WriteLine(string outputMessage)
        {
            File.AppendAllText("Robot-output.txt", outputMessage + Environment.NewLine);
        }

        #endregion IRobotOutputter Interface Methods
    }
}

This again is incredibly cool, for the pure fact that the reliance on System.IO is not forced upon robot type implementations and is fully tucked away and packaged based upon an interface, loosely-coupled dependency. Robots ‘output’, but have no reliance on knowing how that output is performed, very nice!

Right back near the beginning of this post you’ll remember that the IRobotOutputter interface was mapped, during Ninject module configuration, to these two concrete types depending upon whether it was being injected into ISmallRobot or ILargeRobot supporting types. We’ll see that in action below, so hang on in there.

Running the Program

Here are the results, based on our Ninject container configuration and module setup, in motion.

First up, a breakpoint set within the LargeRobotFactory constructor shows that when the TryGet method of the StandardKernel container is called this type is ‘injected’ (based on module configuration) with a BlueWaterPaintMachine and a RocketLauncherAttacher. See the FactoryUtilityModule for reference:

Large Robot Factory Constructor debugging showing concrete types in use at run-time.

Large Robot Factory Constructor Debugging.

Next, robot-based type DI kicks in when test robots are created to be placed on a factories production line. Small and Large robots are injected with, as per the RobotModule Ninject configuration module, RobotOutput and RobotFileOutput types respectively. I’ve called the GetHashCode method in the Immediate Window to illustrate, on two different constructor calls for each robot type, that the same instance of an IRobotOutputter supporting type has been supplied (see the WhenInjectedInto method usage in the RobotModule class for full details again):

Small Robot Constructor debugging showing concrete types being passed in.

Small Robot Constructor Debugging.

Large Robot Constructor debugging showing concrete types being passed in.

Large Robot Constructor Debugging.

We’ve reached (well, nearly) the end of this rather large post…and we have output! The factory has gone to work and painted/armed our robots. Once deployed, they have had their move, speak, attack, sneak and crush functionality triggered. Output of each robot has been determined via DI configuration; small robots have written output to the console and large robots have, as expected, placed output in a file:

Robot factory application output in full.

Robot Factory Application Output.

That hopefully gives you a good primer for configuring Ninject and binding interfaces to implementations (illustrating some of the more common features), ultimately to use DI for your projects.

If you want to have a bit more of a read up then check out the documentation here:

Ninject Documentation

Thanks for reading, this (looking back over it now) has been a bit of a beast of a post again; a massive pat on the back if you’ve read the lot, always appreciated.

All the best and until the next time!