Ninject 4.0.0-beta-0134 抛出 'A cyclical dependency was detected between the constructors of two services'
Ninject 4.0.0-beta-0134 throws 'A cyclical dependency was detected between the constructors of two services'
今天我将我们的 Ninject 依赖从 3.3.4 更新到 4.0.0-beta-0134,但现在它在装饰器模式中抛出了一个循环依赖异常:
`未处理的异常:Ninject.ActivationException:使用从 Program+IService 到 Program+Service 的条件绑定激活 Program+IService 时出错
在两个服务的构造函数之间检测到循环依赖。
激活路径:
2) Program+ServiceDecorator
类型构造函数的参数服务注入依赖Program+IService
- 请求程序+IService
建议:
- 确保您没有声明 Program+IService 对任何服务实现的依赖。
- 考虑将这些服务合并为一个服务以消除循环。
- 使用属性注入代替构造函数注入,并实现IInitializable
如果在注入 属性 值后需要将初始化逻辑设为 运行。
`
示例代码如下:
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();
}
}
它似乎不喜欢在 Ninject 模块中使用 WhenInjectedInto
。我发现了其他类似的问题,但是 none 其中 WhenInjectedInto
不起作用。
解决此问题的一种方法是将服务参数类型从 IService
更改为 Service
,但这破坏了使用装饰器的大部分原因。
你们知道另一个 solution/workaround 吗?
不清楚您打算如何使用此示例中的装饰器,但一种可能是对装饰器应用一个新接口,该接口又继承自 IService
.
public interface IServiceDecorator : IService { }
public interface IService
{
void Serve();
}
public class Service : IService
{
public void Serve() { }
}
public class ServiceDecorator : IServiceDecorator
{
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>().InSingletonScope();
Bind<IService>().To<Service>().WhenInjectedInto<ServiceDecorator>().InSingletonScope();
Bind<IServiceDecorator>().To<ServiceDecorator>().InSingletonScope();
}
}
再次通过后,问题实际上是由使用 .WhenInjectedInto<ServiceDecorator>
引起的,因为绑定之间没有区别。
另一种方法是简单地使用 Bind<IService>().To<Service>().InSingletonScope();
,然后将 BindingConfiguration.Condition
添加到装饰器以处理 Get<ServiceDecorator>()
用例:
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);
}
}
今天我将我们的 Ninject 依赖从 3.3.4 更新到 4.0.0-beta-0134,但现在它在装饰器模式中抛出了一个循环依赖异常:
`未处理的异常:Ninject.ActivationException:使用从 Program+IService 到 Program+Service 的条件绑定激活 Program+IService 时出错 在两个服务的构造函数之间检测到循环依赖。
激活路径: 2) Program+ServiceDecorator
类型构造函数的参数服务注入依赖Program+IService- 请求程序+IService
建议:
- 确保您没有声明 Program+IService 对任何服务实现的依赖。
- 考虑将这些服务合并为一个服务以消除循环。
- 使用属性注入代替构造函数注入,并实现IInitializable 如果在注入 属性 值后需要将初始化逻辑设为 运行。 `
示例代码如下:
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();
}
}
它似乎不喜欢在 Ninject 模块中使用 WhenInjectedInto
。我发现了其他类似的问题,但是 none 其中 WhenInjectedInto
不起作用。
解决此问题的一种方法是将服务参数类型从 IService
更改为 Service
,但这破坏了使用装饰器的大部分原因。
你们知道另一个 solution/workaround 吗?
不清楚您打算如何使用此示例中的装饰器,但一种可能是对装饰器应用一个新接口,该接口又继承自 IService
.
public interface IServiceDecorator : IService { }
public interface IService
{
void Serve();
}
public class Service : IService
{
public void Serve() { }
}
public class ServiceDecorator : IServiceDecorator
{
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>().InSingletonScope();
Bind<IService>().To<Service>().WhenInjectedInto<ServiceDecorator>().InSingletonScope();
Bind<IServiceDecorator>().To<ServiceDecorator>().InSingletonScope();
}
}
再次通过后,问题实际上是由使用 .WhenInjectedInto<ServiceDecorator>
引起的,因为绑定之间没有区别。
另一种方法是简单地使用 Bind<IService>().To<Service>().InSingletonScope();
,然后将 BindingConfiguration.Condition
添加到装饰器以处理 Get<ServiceDecorator>()
用例:
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);
}
}