Search code examples
ninject

What is NInjects equivalent of TryAdd


In other DI containers, I have observed TryAddScoped, TryAddTransient, TryAddSingleton etc.

The idea behind Try is to avoid registering multiple times. If a service is already registered, then using Try will not attempt to register again I guess.

With inject

Kernel.Bind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();

So is there any Try equivalent in Ninject?


Solution

  • There's no simple equivalent.

    Performing

    Kernel.Bind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
    Kernel.Bind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
    

    will result in in an exception when resolving a IHttpContextAccessor, and when resolving IEnumerable<IHttpContextAccessor> it will return two HttpContextAccessor instances.

    However, you can write your own "Try":

    Checking whether Binding already exists

    if(!Kernel.GetBindings(typeof(IHttpContextAccessor)).Any())
    {
        Kernel.Bind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
    }
    

    Of course you can also write your own extension method for that:

    public static class NinjectBindingExtensions
    {
        public static void TryBind<T>(
            this IKernel kernel,
            Action<IBindingToSyntax<T>> configureBinding)
        {
            if (!kernel.GetBindings(typeof(T)).Any())
            {
                configureBinding(kernel.Bind<T>());
            }
        }
    }
    

    Rebind

    One way to work around the issue is to use .Rebind instead of .Bind. If there's no pre-existing binding it will work just like .Bind. And if there's a pre-existing binding, it will replace it. Thus:

    Kernel.Rebind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
    Kernel.Rebind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
    

    Resolving IHttpContextAccessor will result in one instance of HttpContextAccessor.

    Preventing Duplicate Module Loading

    In case the problem is not with multiple components / NinjectModules creating bindings for the same type, but rather with loading the same NinjectModule twice, you can can prevent duplicate loading by:

    if(!Kernel.HasModule(typeof(MyModule)))
    {
        Kernel.Load<MyModule>();
    }