Using Ninject with static methods

938 views Asked by At

My goal is to use Ninject in my application with static methods. I am aware of the fact that the static methods should not have any dependencies since it is hard from testing point of view. But, in my application I am not in the position to make each method static to non-static. I need to implement DI with minimal changes, i.e. I should change the code at one lance and it should change the implementation everywhere where that method or class is being called. I don't want to use the Service Locator pattern too, considering that is not even a pure DI pattern.

In order to keep all those above points in my mind, I implemented the following set up and it has been working well. I need your thoughts whether I did it correct or not to use Ninject with static methods.

My ASP.NET WebForms set up:

Solution: NinjectPlayGround

Projects:

NinjectPlayGround (Web Project)
NinjectPlayGround.BL (Business Layer)
NinjectPlayGround.Common (POCO layer)

enter image description here

In order to use Ninject I installed Ninject.Web

NinjectWebCommon.cs Code:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(NinjectPlayGround.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(NinjectPlayGround.App_Start.NinjectWebCommon), "Stop")]

namespace NinjectPlayGround.App_Start
{
    using System;
    using System.Web;

    using Microsoft.Web.Infrastructure.DynamicModuleHelper;

    using Ninject;
    using Ninject.Web.Common;
    using NinjectPlayGround.Common;
    using NinjectPlayGround.BL;

    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)
        {
            kernel.Bind<ILogger>().To<DefaultLogger>();

            // Set static properties
            CommonHelper.Logger = kernel.Get<ILogger>();
        }        
    }
}

I added the following two custom lines there:

        kernel.Bind<ILogger>().To<DefaultLogger>();

        // Set static properties
        CommonHelper.Logger = kernel.Get<ILogger>();

CommonHelper is the class which has static methods where I want to use Logger instance.

CommonHelper class code:

using NinjectPlayGround.Common;

namespace NinjectPlayGround.BL
{
    public class CommonHelper
    {
        public static ILogger Logger { get; set; }

        public static void RunCleanUp()
        {
            // Run clean up
            //.....


            Logger.Log("Clean up done");
        }
    }
}

ILogger class code:

namespace NinjectPlayGround.Common
{
    public interface ILogger
    {
        void Log(string message);
    }
}

DefaultLogger class code:

using System.Diagnostics;

namespace NinjectPlayGround.Common
{
    public class DefaultLogger : ILogger
    {
        public void Log(string message)
        {
            Debug.WriteLine(message);
        }
    }
}

Since Ninject attribute is not allowed on static properties like this:

public static ILogger Logger { get; set; }

I set that property via RegisterServices method present in NinjectWebCommon class which is called only once per application start (correct me if I am wrong here)

        // Set static properties
        CommonHelper.Logger = kernel.Get<ILogger>();

From UI this helper method is called like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Ninject;
using NinjectPlayGround.BL;

namespace NinjectPlayGround
{
    public partial class _default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            CommonHelper.RunCleanUp();
        }
    }
}

Al the above setup is working fine i.e if I change the DefaultLogger to PersistentLogger (which is another implementation of ILogger)

  kernel.Bind<ILogger>().To<DefaultLogger>();

to

 kernel.Bind<ILogger>().To<PersistentLogger>(); 

I can see PersistentLogger being called instead of DefaultLogger without making any mess/changes in the CommonHelper class.

Is this the correct way to use Ninject with static methods?

Is this how I need to set all static properties which I need to set via DI in RegisterServices method of NinjectWebCommon class?

Will I face any difficulties with this kind of implementation?

EDIT: I have already gone through Ninject and static classes - how to? which is way theoritical. I have asked with full practical implementation of using staic methods with Ninject. Further, that question is for static class, in my casse it is not static class instead is static method.

0

There are 0 answers