将IServiceProvider
注入服务类是一种不好的做法,作为在ASP.NET Core 2.0中获取可选依赖项的方法吗?这会中断Explicit Dependency Principal吗?
我的课程需要一个可选服务,EventBus。如果EventBus已注册,我希望服务类发布一个事件,如果不是简单地忽略它。
public class SomeService {
private readonly IServiceProvider _serviceProvider;
public SomeService(IServiceProvider serviceProvider) {
_serviceProvider = serviceProvider;
}
public SomeAction() {
var eventBus = _serviceProvider.GetService(typeof(IEventBus)) as IEventBus;
if (eventBus != null) {
eventBus.publish("SomeAction Happened!");
}
}
}
我无法看到如何使用内置的IoC Container of ASP.NET Core 2.0创建可选的依赖项。
编辑:有关如何在ASP.NET Core中实现可选依赖项的任何建议吗?或者在没有反模式的情况下获得相同效果的任何其他策略?
答案 0 :(得分:2)
如果方法直接需要它以使其正常运行,则不会被视为可选。
它应该明确地作为依赖注入
public class SomeService {
private readonly IEventBus eventBus;
public SomeService(IEventBus eventBus) {
this.eventBus = eventBus;
}
public SomeAction() {
if (eventBus != null) {
eventBus.publish("SomeAction Happened!");
}
//...
}
}
否则请考虑将其作为可选依赖项
显式传递给方法public SomeAction(IEventBus eventBus = null) {
if (eventBus != null) {
eventBus.publish("SomeAction Happened!");
}
//...
}
显式依赖关系原则声明:
方法和类应 明确要求 (通常通过方法参数或 构造函数参数) 按顺序需要的任何协作对象 正常运作 。
强调我的
注入IServiceProvider
被视为反模式,因为它遵循服务定位器模式。
例如,如果依赖类也被用作工厂,则会有一些例外情况。
答案 1 :(得分:1)
注入IServiceProvider
是Service Locator anti-pattern的实现。防止这样做。依赖性也不应是optional。这引入了复杂性。相反,请使用Null Object pattern。使依赖必需,简化了消费者及其测试。
换句话说,SomeService
应如下所示:
public class SomeService {
private readonly IEventBus _bus;
public SomeService(IEventBus bus) {
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
}
public SomeAction() {
eventBus.publish("SomeAction Happened!");
}
}
在Composition Root中,如果不存在实际实施,则使用NullEventBus
实施。这应该像这样简单:
public class NullEventBus : IEventBus
{
public void publish(string message) {
// do nothing.
}
}
由于此实现不执行任何操作,因此可以将其注入所有使用者。