adrianhesketh.com

Migrating from Ninject to Simple Injector

OK, so it’s time to part ways with Ninject. It’s too slow [0], and it doesn’t want to change [1].

Ninject was fast enough at first, but as apps get bigger, its performance and CPU cost get too high.

Simple Injector has a near-parity feature set (support for MVC filters isn’t quite as strong), great documentation and excellent performance.

// Ninject
private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
    kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

    // Singleton
    kernel.Bind<ILog>().ToMethod(c => LogManager.GetLogger(typeof(ProjectService))).InSingletonScope();
    // WCF Scope
    // Done by default in Ninject when you use the WCF package.
    kernel.Bind<IEntities>().To<Entities>();
    kernel.Bind<IAssetManager>().To<AssetManager>();

    return kernel;
}

// Simple Injector
private static void Start()
{
    // Create the container as usual.
    var container = new Container();

    // Register your types.
    // Singleton.
    container.RegisterSingle<ILog>(() => LogManager.GetLogger(typeof(ProjectService)));
    // WCF Service Scope. This is different to Ninject, because using this Lifecycle in 
    // Simple Injector will result in only a single concrete object being created per WCF
    // operation whereas Ninject can create multiple objects, but scoped to the WCF operation.
    container.RegisterPerWcfOperation<IEntities, Entities>();
    // Transient Scope.
    container.Register<IRepository, Repository>();

    // Register the container to the SimpleInjectorServiceHostFactory.
    SimpleInjectorServiceHostFactory.SetContainer(container);
}

Migrating the setup is also pretty straightforward.

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

// Once it's building, rename the class away from Ninject.
public static class NinjectWebCommon
{
    // -- Ninject
    // private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    public static void Start()
    {
        // -- Ninject
        /*
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
        */
        // ++ Simple Injector
        CreateContainer();
    }

    public static void Stop()
    {
        // -- Ninject.
        // bootstrapper.ShutDown();
    }

    // -- Ninject
    /*
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);
        return kernel;
    }
    
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<ILog>().ToMethod(c => LogManager.GetLogger(typeof(NinjectWebCommon)));
        kernel.Bind<IEntities>().To<Entities>();
    }        
    */
    
    // ++ Simple Injector
    private static Container CreateContainer()
    {
        // Create the container as usual.
        var container = new Container();

        RegisterServices(container);

        // Setup MVC.
        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
        container.RegisterMvcIntegratedFilterProvider();
        DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));

        // Setup WebApi.
        container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
        GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

        // Register filters (if you've used them).
        RegisterGlobalFilters(GlobalFilters.Filters, container);
        RegisterWebApiFilters(GlobalConfiguration.Configuration.Filters, container);

        // Setup WCF.
        SimpleInjectorServiceHostFactory.SetContainer(container);

        return container;
    }

    private static void RegisterServices(Container container)
    {
        container.RegisterSingle<ILog>(() => LogManager.GetLogger(typeof(NinjectWebCommon)));
        container.Register<IEntities, Entities>();
    }

    public static void RegisterGlobalFilters(GlobalFilterCollection filters, Container container)
    {
        filters.Add(container.GetInstance<SessionFilter>());
    }

    private static void RegisterWebApiFilters(System.Web.Http.Filters.HttpFilterCollection httpFilterCollection, Container container)
    {
    }
}

Hope it helps someone else…