I am creating a PersonalityConfiguration class which I want to be a Singleton, and for the most part the Singleton binding works fine. Except for when this "Singleton" is binded through its IPersonalityProvider interface in the Constructor of a Class. When that Binding is Injected, it is not the Singleton, not the same instance of PersonalityConfiguration but rather a new Instance each time. How would I bind the same Singleton to the dependent classes through the IPersonalityProvider interface?
I have the following Inteface and Class Definitions
Interface IPersonalityProvider
interface IPersonalityProvider
{
void BeHappy();
}
Class PersonalityConfiguration
class PersonalityConfiguration : IPersonalityProvider
{
private int m_personalityScale = 0;
public PersonalityConfiguration()
{
m_personalityScale = 0;
}
public void BeHappy()
{
throw new NotImplementedException();
}
}
Class Person
class Person
{
public Person(IPersonalityProvider personality)
{
Personality = personality;
}
public IPersonalityProvider Personality { get; set; }
}
My Ninject Module is as follows
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
}
}
2 Answers 2
The clean way to achieve what you want is by one single binding:
Bind<IPersonalityProvider, PersonalityConfiguration>()
.To<PersonalityConfiguration>()
.InSingletonScope();
this means whenever ninject is requested to return an IPersonalityProvider or an PersonalityConfiguration it will return the same (singleton) instance of PersonalityConfiguration.
I've 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();
}
}
}
}
4 Comments
Assert and xUnit instead of a main method) and i neither have an issue with an activation nor with the verifications. I've dumped my whole code into the answer. What's the exception message saying?ActivationException stating that there are multiple matching bindings...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>();
}
}
Comments
Explore related questions
See similar questions with these tags.
PersonalityConfigurationand the second hasIPersonalityProvider. Ninject will simply lookup a resolution based on the key in this dictionary and those two registrations are not related in any way. What Ninject is concerned they are completely different, even though they share the same implementation type.