我有一个.net微服务,它有一个服务A,它有一个InstancePerLifetimeScope。服务A被注入到MessageService(单例服务)中。
public class MessageService
{
private readonly ServiceA serviceA;
public MessageService(ServiceA serviceA)
{
this.serviceA = serviceA;
}
public void ProcessItem(ItemClass item)
{
serviceA.Proccess(item);
}
}
通过这种方式,ServiceA将成为任何调用它的线程的单例。 要实现InstancePerLifetimeScope,我会:
public class MessageService
{
private readonly IContainer container;
public MessageService(IContainer container)
{
this.container = container;
}
public void ProcessItem(ItemClass item)
{
using (var scope = container.BeginLifetimeScope())
{
scope.Resolve<ServiceA>().Proccess(item);
}
}
}
这是好习惯吗?我读到这是服务定位器模式,被认为是反模式。将容器直接传递到服务中作为注射剂也不是最好的事情。
public class ServiceAFactory
{
private readonly IContainer container;
public ServiceAFactory(IContainer container)
{
this.container = container;
}
public IServiceA swapsService CreateService()
{
using (var scope = container.BeginLifetimeScope())
{
return scope.Resolve<IServiceA>();
}
}
}
答案 0 :(得分:3)
防止在您的应用程序代码中使用容器,并将其专门用作Composition Root的一部分。有很多方法可以做到这一点,因此没有一个答案,但通常你想从业务代码中提取处理Container的代码。
在您的简单示例中,似乎所有类都与容器相关,因此这意味着将其完全移动到Composition Root。由于组合根应该depend on everything else,而应用程序代码不应该依赖于组合根,这意味着其他代码不能调用MessageService
。通过引入抽象:IMessageService
:
public class MessageService : IMessageService
{
...
}
接口应该在应用程序级别定义,即在Composition Root中的实现。
如果MessageService
包含业务逻辑,事情就会变得更加复杂。您将业务逻辑与Container相关逻辑分开。以下是如何处理此问题的一些想法:
MessageService
中的容器内容提取到注入MessageService
的新服务中。ServiceA
工厂,但要验证工厂是否is the right abstraction。MessageService
,进入ServiceA
周围的装饰器/代理。这使得生活方式不匹配对ServiceA
和MessageService
都无动于衷。这包括定义ServiceA
周围的抽象,让MessageService
依赖于此,并从装饰器的ServiceA
方法中解析具体的Proccess
。答案 1 :(得分:1)
我同意this other answer,因为您不应将应用程序代码绑定到DI容器细节,例如IContainer
。
使用Autofac,您可以将工厂Func<ServiceA>
(而不是ServiceA
)注入MessageService
。只要您在容器中注册ServiceA
,Autofac就会自动生成这样的工厂功能。
来自Autofac关于implicit relationship type Func<B>
的文档:
“使用自动生成的工厂可以让您有效地调用[
Resolve<B>()
]而无需将您的组件绑定到Autofac。[...]“使用此关系类型尊重生命周期范围。如果您将[
B
]注册为InstancePerDependency()
并多次调用Func<B>
,则每次都会获得一个新实例。但是,如果您将[B
]注册为SingleInstance()
并调用Func<B>
多次解析对象,则每次都会获得相同的对象实例。“
(我的轻微改动或遗漏放在方括号内。)