Basic dependency injection with Castle Windsor

I’ve already blogged about dependency injection using Castle Windsor in a previous article:

Registering many like types in Castle Windsor

…without giving any of the details around how to set up dependency injection in the first place. This post aims to put that right by demonstrating a basic “Hello World” for those new to dependency injection with Castle Windsor. My example application will simply write the current date and time to the screen using a console application.

I’ve created a solution called BasicDependencyInjection and added a console application with the same name. Don’t forget to change the client profile in your console application as described in a previous post.

I’ve used NuGet to add Castle Windsor to the console application.

My starting solution now looks like this:

Basic DI 01

To this I’ve added a class called Injector in a folder called DependencyInjection:

Basic DI 02

The code in this file is as follows:

using Castle.Windsor;
using Castle.Windsor.Installer;
using Castle.MicroKernel.Registration;

namespace BasicDependencyInjection.DependencyInjection
{
    public static class Injector
    {
        private static readonly object InstanceLock = new object();

        private static IWindsorContainer instance;

        public static IWindsorContainer Instance
        {
            get
            {
                lock (InstanceLock)
                {
                    return instance ?? (instance = GetInjector());
                }
            }
        }

        private static IWindsorContainer GetInjector()
        {
            var container = new WindsorContainer();

            container.Install(FromAssembly.This());

            RegisterInjector(container);

            /* Register more components here */
            
            return container;
        }
        
        private static void RegisterInjector(WindsorContainer container)
        {
            container.Register(
                Component.For<IWindsorContainer>()
                .Instance(container));
        }
    }
}

This is using a take on the singleton pattern to ensure there can only ever be one injector in the application. Note that the class also uses simple thread-locking to ensure that the singleton pattern isn’t bypassed by multiple threads requesting an instance at the same time.

Aside: These days the singleton pattern is considered bad practice. I believe the reason for this is that anything that would traditionally have been created using this pattern should now be injected. However, there is no way to “inject the injector” so I think use of the singleton pattern for this specific task is acceptible. I’d be interested to hear other opinions on this.

At the moment the only thing the injector can resolve is itself. We’ll add to the injector later on in the example. Next we need to create some test dependencies to inject.

When doing demonstrations using dependency injection I like to involve the current date and time as this is a classic textbook example of a dependency, and one that is often overlooked. If you’re hardcoding DateTime.Now statements throughout your code you haven’t removed all your dependencies! Other than making code loosely coupled one of the main advantages of dependency injection is that code is more testable. If you hardcode DateTime.Now you make unit testing much harder as test data needs to be generated each time to reflect the date on which the tests are being ran.

For dependency injection to work we need a class and an interface for each dependency, so I’m going to add Watch and IWatch to the application as follows:

Basic DI 03

These contain the following simple code:

using System;

namespace BasicDependencyInjection
{
    public interface IWatch
    {
        DateTime GetTime();
    }
}
using System;

namespace BasicDependencyInjection
{
    public class Watch : IWatch
    {
        public DateTime GetTime()
        {
            return DateTime.Now;
        }
    }
}

I’m also going to include a dependency to actually write the date and time to the screen, using ITimeWriter and TimeWriter:

Basic DI 04

…which are as follows:

namespace BasicDependencyInjection
{
    public interface ITimeWriter
    {
        void WriteTime();
    }
}
using System;

namespace BasicDependencyInjection
{
    public class TimeWriter : ITimeWriter
    {
        public IWatch Watch { get; set; }

        public void WriteTime()
        {
            Console.WriteLine("The current time is: {0}", Watch.GetTime());
        }
    }
}

The TimeWriter class has a property of Type IWatch called Watch, which doesn’t appear to be assigned a value anywhere in the code. One of the most confusing things for developers new to dependency injection is where these properties actually get set. When debugging through existing codebases with dependency injection enabled properties such as these do have values assigned but the assignment cannot be found anywhere. It’s like magic! The thing to remember is that when a reference is resolved using a dependency injecton framework, all contructor arguments and properties that have an interface that the injector knows about are assigned the object associated with the interface.

Now that dependencies have been added, we need to make sure the injector knows about them. I’ve updated the injector class as follows:

using Castle.Windsor;
using Castle.Windsor.Installer;
using Castle.MicroKernel.Registration;

namespace BasicDependencyInjection.DependencyInjection
{
    public static class Injector
    {
        private static readonly object InstanceLock = new object();

        private static IWindsorContainer instance;

        public static IWindsorContainer Instance
        {
            get
            {
                lock (InstanceLock)
                {
                    return instance ?? (instance = GetInjector());
                }
            }
        }

        private static IWindsorContainer GetInjector()
        {
            var container = new WindsorContainer();

            container.Install(FromAssembly.This());

            RegisterInjector(container);
            RegisterTimeComponents(container);
            
            return container;
        }
        
        private static void RegisterTimeComponents(WindsorContainer container)
        {
            container.Register(
                   Component.For()
                   .ImplementedBy(typeof(Watch))
                   .LifeStyle.Singleton);

            container.Register(
                   Component.For()
                   .ImplementedBy(typeof(TimeWriter))
                   .LifeStyle.Singleton);
        }

        private static void RegisterInjector(WindsorContainer container)
        {
            container.Register(
                Component.For<IWindsorContainer>()
                .Instance(container));
        }
    }
}

This now maps IWatch to Watch and ITimeWriter to TimeWriter.

All that remains is to include some code in the program:

using System;
using BasicDependencyInjection.DependencyInjection;

namespace BasicDependencyInjection
{
    public static class Program
    {
        public static void Main()
        {
            var timePrinter = Injector.Instance.Resolve();
            timePrinter.WriteTime();

            Console.WriteLine();
            Console.WriteLine("Press RETURN to exit...");
            Console.ReadLine();
        }
    }
}

…and run the thing. Which yields:

Basic DI 05

…as expected.

That concludes my dependency injection “Hello World”.

Leave a Reply

Your email address will not be published. Required fields are marked *