C# Autofac生存期范围使用

C# Autofac生存期范围使用,c#,.net,dependency-injection,autofac,C#,.net,Dependency Injection,Autofac,我有一个.net微服务,它有一个服务a,它有一个InstancePerLifetimeScope。服务A被注入MessageService(单例服务) 通过这种方式,ServiceA正在成为任何调用它的线程的单例。 要实现InstancePerLifetimeScope,我需要: public class MessageService { private readonly IContainer container; public MessageService(IContaine

我有一个.net微服务,它有一个服务a,它有一个InstancePerLifetimeScope。服务A被注入MessageService(单例服务)

通过这种方式,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);
        }
    }
}
公共类消息服务
{
专用只读IContainer容器;
公共消息服务(IContainer容器)
{
this.container=容器;
}
public void ProcessItem(ItemClass项)
{
使用(var scope=container.BeginLifetimeScope())
{
scope.Resolve().process(项);
}
}
}
这是好的做法吗?我听说这是服务定位器模式,被认为是反模式。另外,将容器作为可注入的直接传递到服务中并不是最好的做法

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>();
            }
        }
    }
公共类服务工厂
{
专用只读IContainer容器;
公共服务工厂(IContainer容器)
{
this.container=容器;
}
公共IServiceA SwapService CreateService()
{
使用(var scope=container.BeginLifetimeScope())
{
返回scope.Resolve();
}
}
}

禁止在应用程序代码中使用容器,并将其作为应用程序的一部分专门使用。有很多方法可以做到这一点,因此没有一个单一的答案,但通常您希望从业务代码中提取处理容器的代码

在您的简单示例中,类所做的一切似乎都与容器相关,因此这意味着将其完全移动到组合根。由于组合根应该是,而应用程序代码不应该依赖于组合根,这意味着其他代码不能调用
MessageService
。通过引入一个抽象:
IMessageService
,可以轻松优雅地解决这个问题:

public class MessageService : IMessageService
{
    ...
}
接口应该在应用程序级别定义,实现在合成根目录中

如果
MessageService
也包含业务逻辑,事情就会变得更加复杂。您需要将业务逻辑与容器相关逻辑分开。以下是一些处理方法:

  • 将容器内容从
    MessageService
    提取到注入
    MessageService
    的新服务中
  • 将工厂用于
    ServiceA
    ,该工厂允许创建新实例,但要验证工厂是否可用
  • 将容器逻辑移出
    MessageService
    ,移动到
    ServiceA
    周围的装饰器/代理中。这使得生活方式不匹配对
    ServiceA
    MessageService
    都不起作用。这涉及到围绕
    ServiceA
    定义一个抽象,让
    MessageService
    依赖于此,并从decorator的
    过程
    方法中解析具体的
    ServiceA

禁止在应用程序代码中使用容器,并将其作为应用程序的一部分专门使用。有很多方法可以做到这一点,因此没有一个单一的答案,但通常您希望从业务代码中提取处理容器的代码

在您的简单示例中,类所做的一切似乎都与容器相关,因此这意味着将其完全移动到组合根。由于组合根应该是,而应用程序代码不应该依赖于组合根,这意味着其他代码不能调用
MessageService
。通过引入一个抽象:
IMessageService
,可以轻松优雅地解决这个问题:

public class MessageService : IMessageService
{
    ...
}
接口应该在应用程序级别定义,实现在合成根目录中

如果
MessageService
也包含业务逻辑,事情就会变得更加复杂。您需要将业务逻辑与容器相关逻辑分开。以下是一些处理方法:

  • 将容器内容从
    MessageService
    提取到注入
    MessageService
    的新服务中
  • 将工厂用于
    ServiceA
    ,该工厂允许创建新实例,但要验证工厂是否可用
  • 将容器逻辑移出
    MessageService
    ,移动到
    ServiceA
    周围的装饰器/代理中。这使得生活方式不匹配对
    ServiceA
    MessageService
    都不起作用。这涉及到围绕
    ServiceA
    定义一个抽象,让
    MessageService
    依赖于此,并从decorator的
    过程
    方法中解析具体的
    ServiceA
我同意你的观点,你不应该把你的应用程序代码和DI容器的细节联系起来,比如
IContainer

使用Autofac,您可以将工厂
Func
(而不是
ServiceA
)注入
MessageService
。只要您在容器中注册了
ServiceA
,Autofac就会自动为您生成这样一个工厂函数

来自Autofac关于以下各项的文档:

“使用自动生成的工厂可以让您有效地调用[
Resolve()
],而无需将组件绑定到Autofac。[…]

“使用此关系类型尊重生存期范围。如果将[
B
]注册为
InstancePerDependency()
并多次调用
Func
,每次都会得到一个新实例。但是,如果将[
B
]注册为
SingleInstance()
,并多次调用
Func
解析对象,则每次都会得到相同的对象实例。”

(我的轻微改动或遗漏放在方括号内。)

我同意,你不应将你的申请与