Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Singleton Scope binding not working as intended

I am using the ninject mvc3 plugin with my web api application. I have a binding that looks like:

kernel.Bind<IFoo>().To<Foo>().InSingletonScope();

It is my interpretation that the kernal will create exactly one instance of Foo and reuse it appropriately. By putting a breakpoint in Foo's constructor, I can clearly see that it is getting called once per request, and I cannot explain why.

My only guess is that somehow a new kernel is getting created per request, but that doesn't appear to be the case, as the CreateKernel method which sets the global dependency resolver is only getting run once in the application lifetime.

I am using some code taken from this post to make ninject play nice with mvc 4. Because of framework changes, I had to make an additional wrapper that I assign to GlobalConfiguration.Configuration.DependencyResolver:

public class NinjectResolver : NinjectScope, IDependencyResolver
{
    private readonly IKernel _kernel;
    public NinjectResolver(IKernel kernel)
        : base(kernel)
    {
        _kernel = kernel;
    }
    public IDependencyScope BeginScope()
    {
        return new NinjectScope(_kernel.BeginBlock());
    }
}

What am I doing wrong?

like image 262
captncraig Avatar asked Oct 08 '12 15:10

captncraig


2 Answers

Certainly arriving late to this thread but it just happened to me with a Windows Service hosting OWIN for Web API controllers and resolving dependencies with Ninject, InSingletonScope() wasn't working until I did the following:

var kernel = new StandardKernel();
...
kernel.Bind<Foo>().ToSelf().InSingletonScope();
kernel.Bind<IFoo>().ToMethod(context => context.Kernel.Get<Foo>());
...

// Controllers ask for the dependency as usual...
public class SomeController : ApiController
{
    readonly IFoo _foo;

    public SomeController(IFoo foo)
    {
        _foo = foo;
    }
...

Hope this helps

like image 168
Francisco Javier Banos Lemoine Avatar answered Oct 20 '22 03:10

Francisco Javier Banos Lemoine


Like previously mentioned it does look like a bug.
One option is to simply implement a singleton extension method yourself:

public static class NinjectSingletonExtension
{
    public static CustomSingletonKernelModel<T> SingletonBind<T>(this IKernel i_KernelInstance)
    {
        return new CustomSingletonKernelModel<T>(i_KernelInstance);
    }
}

public class CustomSingletonKernelModel<T>
{
    private const string k_ConstantInjectionName = "Implementation";
    private readonly IKernel _kernel;
private static object padlock = new Object();

    private T _concreteInstance;


    public CustomSingletonKernelModel(IKernel i_KernelInstance)
    {
        this._kernel = i_KernelInstance;
    }

    public IBindingInNamedWithOrOnSyntax<T> To<TImplement>(TImplement i_Constant = null) where TImplement : class, T
    {
        _kernel.Bind<T>().To<TImplement>().Named(k_ConstantInjectionName);
        var toReturn =
            _kernel.Bind<T>().ToMethod(x =>
                                       {
                                           if (i_Constant != null)
                                           {
                                               return i_Constant;
                                           }

                                           if (_concreteInstance == null)
                       {
                       lock (padlock)
                       {
                        if (_concreteInstance == null)
                        {
                            _concreteInstance = _kernel.Get<T>(k_ConstantInjectionName);
                        }
                           }
                       }


                                           return _concreteInstance;
                                       }).When(x => true);

        return toReturn;
    }
}

And then simply use:

i_Kernel.SingletonBind<T>().To<TImplement>();

Rather then

i_Kernel.Bind<T>().To<TImplement>().InSingletonScope();


like image 45
Tomer Avatar answered Oct 20 '22 03:10

Tomer