Simple & Quick setup for Dependency Injection using Ninject

Spread the love

Intro

Dependency Injection, DI in short, also known as Inversion-of-Control, is one of the core principles of SOLID programming and one of my favorite techniques to write software. It is a software design pattern that allow us to develop loosely coupled code, thus reducing the coupling between various software components.

It is important to remember that a major facet of object-oriented programming is “loose coupling”. This means that objects should have the minimum number of dependencies they need in order to do their job. An object’s dependencies should be on interfaces as opposed to “concrete” objects (A concrete object is an object created by the ‘new’ keyword).

With loose coupling, you enable easier maintainability and greater reusability. Moreover, you can feature “mock” objects designed to take the place of costly services.

There are three types of dependency injection:

  • Constructor Injection
  • Setter Injection
  • Method Injection

In this post, I’ll talk about the first one, the constructor injection, so let’s begin!

Step 1 – Preparations

In order to use dependency injection, you need to make sure the class you want to be injected is implementing an interface.

example:
public interface IApplicationLayer { };
public class ApplicationLayer : IApplicationLayer

Step 2 – Adding the Ninject to the solution

Install the needed packages from nuget

  • Ninject
  • Ninject.MVC5
  • Ninject.Web.Common
  • Ninject.Web.Common.WebHost

Step 3 – Verify NinjectWebCommon class

After you add the needed Ninject packages from NuGet, the install script should generate a class called “NinjectWebCommon” under App_Start folder.
The generated class should look something like this:

public static class NinjectWebCommon 
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start() 
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }
        
        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }
        
        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            try
            {
                kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
                kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

                RegisterServices(kernel);
                return kernel;
            }
            catch
            {
                kernel.Dispose();
                throw;
            }
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            
		}
	}

Step 4 – Creating the DI layer

Create a class derives from NinjectModule, which will define the binding between the contracts (Interfaces) and the class that implements them. Since this class actually does the binding, I’d use it inject any configurations to the implemented classes constructors.

As can be seen in the example below, I am using a dictionary to hold configuration values that I loaded earlier. I fetch the needed value I want to inject from the dictionary, then provide it to the binding using the WithConstructorArgument extension.

public class SolutionModule : NinjectModule
	{
		string someConfigurationValue ;

		public SolutionModule(Dictionary Config)
		{
			Config.TryGetValue("SomeConfigurationValue", out someConfigurationValue );
		}

		public override void Load()
		{
			// Bind the ApplicationLayer class to the IApplicationLayer interface.
			// ApplicationLayer class must implement IApplicationLayer interface
			 Bind<IApplicationLayer>().
				To<ApplicationLayer>().
				WithConstructorArgument("injectedConfigurationValue", someConfigurationValue);
		}
	}

Attention: Make sure the parameter name that we are injecting values into in the constructor matches the one you are using with WithConstructorArgument (case sensitive)

Step 5 – Load the DI modules

The RegisterServices method is where we should be loading any configuration values that needs to be injected to the implementing classes constructors.

private static void RegisterServices(IKernel kernel)
	{
		string SomeConfigurationValue = ConfigurationManager.AppSettings.Get("SomeSettingInAppConfig");

		Dictionary<string, string> Config = new Dictionary<string,string>();
		Config.Add("SomeConfigurationValue", SomeConfigurationValue);

		// You can add as many module as you need
		var modules = new List
		{
			new SolutionModule(Config)
		};

		kernel.Load(modules);
	}

And that’s it!, now every time you use IApplication interface, during runtime, the DI library (in our case Ninject) will instantiate and inject the proper object.

Appendix – Setting up the Log4Net Ninject module

If you are using Log4Net to do the logging for you, here’s a quick setup I grabbed from the web:

public class LoggingModule : NinjectModule
    {
        public override void Load()
        {
            Bind<log4net.ILog>().ToMethod(x => log4net.LogManager.GetLogger(GetParentTypeName(x)))
                .InSingletonScope();

            Bind<ILocalLogger>().To<LocalLogger>()
                .InSingletonScope();
        }

        private string GetParentTypeName(IContext context)
        {
            //return context.Request.ParentContext.Request.ParentContext.Request.Service.FullName;
            return context.Request.ParentRequest.ParentRequest.Target.Member.DeclaringType.ToString();
        }
    }

Leave a Reply

Your email address will not be published.