Today I updated our Ninject dependency from 3.3.4 to 4.0.0-beta-0134, but now it throws a circular dependency exception in decorator pattern:
`Unhandled Exception: Ninject.ActivationException: Error activating Program+IService using conditional binding from Program+IService to Program+Service A cyclical dependency was detected between the constructors of two services.
Activation path: 2) Injection of dependency Program+IService into parameter service of constructor of type Program+ServiceDecorator
Suggestions:
Here is sample code:
public static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Load(new IocConfig());
kernel.Get<IService>().Serve();
}
internal interface IService
{
void Serve();
}
public class Service : IService
{
public void Serve() { }
}
public class ServiceDecorator : IService
{
private readonly IService _service;
public ServiceDecorator(IService service) => _service = service;
public void Serve() => _service.Serve();
}
public class IocConfig : NinjectModule
{
public override void Load()
{
Bind<IService>().To<Service>().WhenInjectedInto<ServiceDecorator>().InSingletonScope();
Bind<IService>().To<ServiceDecorator>().InSingletonScope();
}
}
It seams like it does not like the use of WhenInjectedInto
in the NinjectModule. I found other similar questions, but none where WhenInjectedInto
was not working.
One way to fix this is to change the service parameter type from IService
to Service
but that destroys much of the reason for using the Decorator.
Do any of you know of another solution/workaround?
After making another pass, it would appear that the issue is actually caused by the use of .WhenInjectedInto<ServiceDecorator>
since there is no differentiation between the bindings.
An alternative is to simply use Bind<IService>().To<Service>().InSingletonScope();
and then add a BindingConfiguration.Condition
to your decorator to handle the Get<ServiceDecorator>()
use case:
public static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Load(new IocConfig());
kernel.Get<IService>().Serve();
kernel.Get<ServiceDecorator>().Serve();
}
public interface IService
{
void Serve();
}
public class Service : IService
{
public void Serve() { Console.WriteLine("service"); }
}
public class ServiceDecorator : IService
{
private readonly IService _service;
public ServiceDecorator(IService service) => _service = service;
public void Serve() { Console.WriteLine("decorator"); _service.Serve(); }
}
public class IocConfig : NinjectModule
{
public override void Load()
{
Bind<IService>().To<Service>().InSingletonScope();
Bind<IService>().To<ServiceDecorator>().InSingletonScope().BindingConfiguration.Condition =
(Ninject.Activation.IRequest request) =>
request.Service == typeof(ServiceDecorator);
}
}