Ninject Singleton is not injected as Singleton in dependent class
I am creating a class PersonalityConfiguration
that I want to be a singleton and for the most part the Singleton binding works great. Except when this "Singleton" is bound through an interface IPersonalityProvider
in the class constructor. When it is Binding Injected, it is not a Singleton, not the same instance PersonalityConfiguration
, but rather a new instance every time. How do I bind the same Singleton with dependent classes through an interface IPersonalityProvider
?
I have the following definitions of integrity and class
IPersonalityProvider interface
interface IPersonalityProvider
{
void BeHappy();
}
PersonalityConfiguration Class
class PersonalityConfiguration : IPersonalityProvider
{
private int m_personalityScale = 0;
public PersonalityConfiguration()
{
m_personalityScale = 0;
}
public void BeHappy()
{
throw new NotImplementedException();
}
}
Classes>
class Person
{
public Person(IPersonalityProvider personality)
{
Personality = personality;
}
public IPersonalityProvider Personality { get; set; }
}
My Ninject module looks like this
class ProgramNinjectModule : NinjectModule
{
public override void Load()
{
Bind<PersonalityConfiguration>().ToSelf().InSingletonScope();
Bind<IPersonalityProvider>().To<PersonalityConfiguration>();
}
}
Here is my main
static void Main(string[] args)
{
using (var nKernel = new StandardKernel(new ProgramNinjectModule()))
{
//Singleton works here
PersonalityConfiguration crazy1 = nKernel.Get<PersonalityConfiguration>();
PersonalityConfiguration crazy2 = nKernel.Get<PersonalityConfiguration>();
Assert.AreEqual(crazy1, crazy2); //True as Expected
//Expecting PersonalityConfig Singleton to bind to Person1 and 2, does not
Person person1 = nKernel.Get<Person>();
Person person2 = nKernel.Get<Person>();
Assert.AreEqual(person1.Personality, person2.Personality); //False, Bombs
//Obviously this works
Person person3 = new Person(crazy1);
Person person4 = new Person(crazy1);
Assert.AreEqual(person3.Personality, person4.Personality); //True as Expected
}
}
source to share
The clean way to achieve what you want is with one binding:
Bind<IPersonalityProvider, PersonalityConfiguration>()
.To<PersonalityConfiguration>()
.InSingletonScope();
this means that whenever ninject is requested to return IPersonalityProvider
or PersonalityConfiguration
, it returns the same (singleton) instance PersonalityConfiguration
.
I have verified that it works correctly using the following code:
using System;
using FluentAssertions;
using Ninject;
using Ninject.Modules;
using Xunit;
namespace NinjectTest.SingletonBoundToMultipleTypes
{
interface IPersonalityProvider
{
void BeHappy();
}
class PersonalityConfiguration : IPersonalityProvider
{
private int m_personalityScale = 0;
public PersonalityConfiguration()
{
m_personalityScale = 0;
}
public void BeHappy()
{
throw new NotImplementedException();
}
}
class Person
{
public Person(IPersonalityProvider personality)
{
Personality = personality;
}
public IPersonalityProvider Personality { get; set; }
}
class ProgramNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IPersonalityProvider, PersonalityConfiguration>()
.To<PersonalityConfiguration>()
.InSingletonScope();
}
}
public class Test
{
[Fact]
public void PerformTest()
{
using (var nKernel = new StandardKernel(new ProgramNinjectModule()))
{
//Singleton works here
PersonalityConfiguration crazy1 = nKernel.Get<PersonalityConfiguration>();
PersonalityConfiguration crazy2 = nKernel.Get<PersonalityConfiguration>();
ReferenceEquals(crazy1, crazy2).Should().BeTrue();
//Expecting PersonalityConfig Singleton to bind to Person1 and 2, does not
Person person1 = nKernel.Get<Person>();
Person person2 = nKernel.Get<Person>();
ReferenceEquals(person1.Personality, person2.Personality)
.Should().BeTrue();
//Obviously this works
Person person3 = new Person(crazy1);
Person person4 = new Person(crazy1);
ReferenceEquals(person3.Personality, person4.Personality)
.Should().BeTrue();
}
}
}
}
source to share
Looks like I used the following binding and it worked
class ProgramNinjectModule : NinjectModule
{
public override void Load()
{
Bind<PersonalityConfiguration>().ToSelf().InSingletonScope();
Bind<IPersonalityProvider>().ToMethod(n => n.Kernel.Get<PersonalityConfiguration>()).WhenInjectedInto<Person>();
}
}
source to share