3

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
 }
 }
asked Jun 26, 2015 at 3:49
1
  • You are making two bindings, which basically means two registrations in the internal dictionary. The first has a key of PersonalityConfiguration and the second has IPersonalityProvider. 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. Commented Jun 26, 2015 at 7:22

2 Answers 2

4

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();
 }
 }
 }
}
answered Jun 26, 2015 at 4:42
Sign up to request clarification or add additional context in comments.

4 Comments

this did not work, gave an "Ninject.ActiviationException" on the first line after "using", PersonalityConfiguration crazy1 = nKernel.Get<PersonalityConfiguration>();
@CodeCowboyOrg it works for me. I've performed the same tests (using FluentAssertions instead of 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?
@CodeCowboyOrg did you leave any of your old bindings? If so, ninject would have thrown an ActivationException stating that there are multiple matching bindings...
You're right, it works. I needed to remove the old bindings. Thank you very much for testing the scenario, I appreciate it.
1

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>();
 }
}
answered Jun 26, 2015 at 4:01

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.