1
votes

I've run into a Ninject issue that I can't quite seem to plumb the depths of. Maybe you can see something obvious that I'm missing. I'm getting a binding error where it wants me to have a binding for Bool:

Ninject.ActivationException: Error activating bool
No matching bindings are available, and the type is not self-bindable.
Activation path:
  5) Injection of dependency bool into parameter realTime of constructor of type SimulatorStateMachine
  4) Injection of dependency ISimulatorStateTriggers into parameter stateMachine of constructor of type InputParser
  3) Injection of dependency InputParser into parameter parser of constructor of type SimulatorCommunicationsChannel
  2) Injection of dependency ICommunicationChannel into property Channel of type SimulatorContext
  1) Request for SimulatorContext

Suggestions:
  1) Ensure that you have defined a binding for bool.
  2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
  3) Ensure you have not accidentally created more than one kernel.
  4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
  5) If you are using automatic module loading, ensure the search path and filters are correct.

   at Ninject.KernelBase.Resolve(IRequest request, Boolean handleMissingBindings)
   at Ninject.KernelBase.Resolve(IRequest request)
   at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent)
   at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target)
   at Ninject.Activation.Providers.StandardProvider.c__DisplayClass15_0.b__0(ITarget target)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Ninject.Activation.Providers.StandardProvider.Create(IContext context)
   at Ninject.Activation.Context.ResolveInternal(Object scope)
   at Ninject.Activation.Context.Resolve()
   at Ninject.KernelBase.Resolve(IRequest request, Boolean handleMissingBindings)
   at Ninject.KernelBase.Resolve(IRequest request)
   at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent)
   at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target)
   at Ninject.Activation.Providers.StandardProvider.c__DisplayClass15_0.b__0(ITarget target)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Ninject.Activation.Providers.StandardProvider.Create(IContext context)
   at Ninject.Activation.Context.ResolveInternal(Object scope)
   at Ninject.Activation.Context.Resolve()
   at Ninject.KernelBase.Resolve(IRequest request, Boolean handleMissingBindings)
   at Ninject.KernelBase.Resolve(IRequest request)
   at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent)
   at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target)
   at Ninject.Activation.Providers.StandardProvider.c__DisplayClass15_0.b__0(ITarget target)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Ninject.Activation.Providers.StandardProvider.Create(IContext context)
   at Ninject.Activation.Context.ResolveInternal(Object scope)
   at Ninject.Activation.Context.Resolve()
   at Ninject.KernelBase.Resolve(IRequest request, Boolean handleMissingBindings)
   at Ninject.KernelBase.Resolve(IRequest request)
   at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent)
   at Ninject.Activation.Strategies.PropertyInjectionStrategy.GetValue(IContext context, ITarget target, IEnumerable`1 allPropertyValues)
   at Ninject.Activation.Strategies.PropertyInjectionStrategy.Activate(IContext context, InstanceReference reference)
   at Ninject.Activation.Pipeline.c__DisplayClass6_0.b__0(IActivationStrategy s)
   at Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map[T](IEnumerable`1 series, Action`1 action)
   at Ninject.Activation.Pipeline.Activate(IContext context, InstanceReference reference)
   at Ninject.Activation.Context.ResolveInternal(Object scope)
   at Ninject.Activation.Context.Resolve()
   at Ninject.KernelBase.Resolve(IRequest request, Boolean handleMissingBindings)
   at Ninject.KernelBase.Resolve(IRequest request)
   at Ninject.ResolutionExtensions.GetResolutionIterator(IResolutionRoot root, Type service, Func`2 constraint, IEnumerable`1 parameters, Boolean isOptional, Boolean isUnique)
   at Ninject.ResolutionExtensions.Get[T](IResolutionRoot root, IParameter[] parameters)
   at TA.SnapCap.Specifications.Contexts.SimulatorTestContextBuilder.Build() in C:\Users\Tim\source\repos\ta.snapcap\TA.SnapCap.Specifications\Contexts\SimulatorTestContextBuilder.cs:line 44
   at TA.SnapCap.Specifications.SimulatorSpecs.when_creating_a_fast_simulator.c.b__5_0() in C:\Users\Tim\source\repos\ta.snapcap\TA.SnapCap.Specifications\SimulatorSpecs\CreationSpecs.cs:line 32

I can't see why it needs that. The object being constructed, SimulatorStateMachine, has a specific binding to a constructor that uses a constant value for the bool argument. I've also tried a variant of this using .WithConstructorArgument().

My entire composition root is included below. If I uncomment the Bind<bool>().ToConstant(false) line, then the error goes away (but if course this is not the behaviour I need). So clearly Ninject is somehow not using the constructor I've specified. Can you see why this is so? I can't and I've gone a bit code-blind...

using System;
using Ninject;
using Ninject.Modules;
using NodaTime;
using TA.Ascom.ReactiveCommunications;
using TA.SnapCap.HardwareSimulator;

namespace TA.SnapCap.Specifications.Contexts
    {
    class SimulatorTestContextBuilder : NinjectModule
        {
        private readonly IKernel testKernel = new StandardKernel();
        string connectionString = "Simulator:Fast";
        Action<SimulatorStateMachine>
            initializeStateMachine = machine => { }; // called to initialize the state machine. DO nothing by default.
        bool openChannel;

        /// <inheritdoc />
        public override void Load()
            {
            //Bind<bool>().ToConstant(false);
            Bind<SimulatorStateMachine>().ToMethod(ctx => new SimulatorStateMachine(true, SystemClock.Instance));
            Bind<IClock>().ToMethod(_ => SystemClock.Instance).InSingletonScope();
            Bind<SimulatorEndpoint>()
                .ToMethod(ctx => SimulatorEndpoint.FromConnectionString(connectionString))
                .InSingletonScope();
            Bind<DeviceEndpoint>().To<SimulatorEndpoint>().InSingletonScope();
            Bind<InputParser>().ToSelf().InSingletonScope();
            Bind<ISimulatorStateTriggers>().To<SimulatorStateMachine>().InSingletonScope();
            Bind<SimulatorCommunicationsChannel>().ToSelf().InSingletonScope();
            Bind<ICommunicationChannel>().To<SimulatorCommunicationsChannel>().InSingletonScope();
            Bind<SimulatorContext>().ToSelf().InSingletonScope();
            }

        public SimulatorContext Build()
            {
            testKernel.Load(this);
            var context = testKernel.Get<SimulatorContext>();
            context.SimulatorChannel.IsOpen = openChannel;
            initializeStateMachine(context.Simulator);
            return context;
            }

        public SimulatorTestContextBuilder WithFastSimulator()
            {
            connectionString = "Simulator:Fast";
            return this;
            }

        public SimulatorTestContextBuilder WithRealtimeSimulator()
            {
            connectionString = "Simulator:Realtime";
            return this;
            }

        public SimulatorTestContextBuilder WithOpenChannel()
            {
            openChannel = true;
            return this;
            }

        public SimulatorTestContextBuilder InClosedState()
            {
            initializeStateMachine = machine =>
                machine.Initialize(new StateClosed(machine), testKernel.Get<InputParser>());
            return this;
            }
        }
    }
1

1 Answers

1
votes

The problem is with your binding of ISimulatorStateTriggers. It should be :

Bind<ISimulatorStateTriggers>()
  .ToMethod(ctx => new SimulatorStateMachine(yourChoiceOfBoolValue, SystemClock.Instance))
  .InSingletonScope();

Your binding of SimulatorStateMachine would be used only if you were to resolve SimulatorStateMachine, which is not the case here. Bindings are not overloads for constructor in this case.