Autofac 创建 2 个服务实例

Autofac create 2 instances of service

当我希望每个 API 请求一个实例时,Autofac 解析为 2 个单独的实例。

我看到一个从控制器到命令处理程序的实例,另一个实例在我的一个域事件处理程序中,域处理程序通过 属性 注入引用调度程序对象。

这里的问题是我没有看到 UserContext 的同一个对象实例,我在域事件处理程序中通过 Web API 控制器注入和修改它调用通过 DomainEvent.dispatcher.Raise();.

我遵循与 Autofac 文档相同的说明。任何人都可以阐明我在这里缺少的东西吗?

//Auotfac registration  
public class AutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
         builder
            .RegisterType<DomainEventDispatcher>()
            .As<IDomainEventDispatcher>().InstancePerLifetimeScope();

         builder
            .RegisterType<DomainEvent>()
            .As<IDomainEvent>).PropertiesAutowired().InstancePerLifetimeScope().AutoActivate();

         builder
            .RegisterType<UserContext>()
            .As<IApplicationContext>().InstancePerLifetimeScope();
    }
}

//My DomainEvent class
//--------------------------
internal class DomainEvent:IDomainEvent
{
    public static IDomainEventDispatcher dispatcher { get;  set; }
}

这将很难弄清楚,因为您没有提供 a Minimal, Complete, and Verifiable Example。该示例和与您的问题相关的所有代码都应该在问题中 - 如果通过评论提出问题...用答案更新您的问题。

也就是说,我可以看出您可能掉入的陷阱。

首先,我看到了这个:

builder
  .RegisterType<DomainEventDispatcher>()
  .As<IDomainEventDispatcher>()
  .InstancePerLifetimeScope();

在 ASP.NET / ASP.NET 核心中,这通常等同于 "one instance per request,",这似乎是您想要去的方向。但是,这意味着 它仅从请求生命周期范围.

中解析

根容器也是一个生命周期范围。这就是解决单例的地方。这也是单例 dependencies 得到解决的地方。 There's a looooot of documentation on lifetime scopes.

这很重要,因为我看到另外两件事引起了一些关注。

首先...

internal class DomainEvent : IDomainEvent
{
    public static IDomainEventDispatcher dispatcher { get;  set; }
}

static 确实与 有关,因为您已将调度程序注册为每个生命周期范围内的实例...但是 static 这里将是线程问题。我假设(虽然无法再次验证,因为缺少 MCVE)您正在做一些事情,以便在收到请求时设置此静态变量。当一次只有一个请求进入时,这在开发中可能很有效。当您有两个请求并且调度程序的一个实例凌驾于另一个实例时,这将是一个非常糟糕的消息。

不要混用静态和按请求。 静态的东西是单例。总是。

第二...

builder
  .RegisterType<DomainEvent>()
  .As<IDomainEvent>()
  .PropertiesAutowired()
  .InstancePerLifetimeScope()
  .AutoActivate();

你有一些看起来应该根据请求创建的东西,但你也有 AutoActivate()。这将在容器构建时从根容器 中解决其中一个问题。我不确定那里发生了什么,也许共享数据连接正在启动之类的,但这意味着您在容器构建时从容器中解析了 DomainEvent 并且该实例 将被缓存,直到容器被处理 因为您指定了每个生命周期范围的实例......而且,容器是一个范围。如果您要在根级别请求其中的第二个(例如对单例的依赖),您将获得这个根级别,而不是每个请求的级别。

我假设 稍后 您还会在某处解析 DomainEvent 对象。如果它们在控制器或其他东西中,它们可能来自请求范围。

因此,您对范围和激活有一组混合的要求。

  • IDomainEventDispatcher 的静态引用,这将是整个应用程序的单例...但是 IDomainEventDispatcher.
  • 的每个生命周期范围注册
  • IDomainEvent 的自动激活,这将在根容器中发生...但是由于每个生命周期范围注册,希望让它成为每个请求。

这里显然也有一个 UserContext 在起作用,但是代码中没有任何内容解释它是如何被消耗的或者它在做什么,所以这部分问题无法解决。

我会推荐:

  • 将对调度程序的 static 引用切换为实例 属性。如果你想让调度器成为一个单例,用 Autofac 将它注册为 SingleInstance
  • 尽可能避免 属性 注入。如果 DomainEvent 需要调度程序,请将其放入构造函数中。这将确保您总能得到一个。 属性 如果不能注入 属性.
  • 注入就不会失败
  • 不要对每个请求的项目使用 AutoActivate。如果您有共享数据连接或需要在容器构建时启动的东西,请将该逻辑分离到某种可以注册为单例的数据提供者。这也将避免根级解析应该是每个请求的东西。