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
。如果您有共享数据连接或需要在容器构建时启动的东西,请将该逻辑分离到某种可以注册为单例的数据提供者。这也将避免根级解析应该是每个请求的东西。
当我希望每个 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
。如果您有共享数据连接或需要在容器构建时启动的东西,请将该逻辑分离到某种可以注册为单例的数据提供者。这也将避免根级解析应该是每个请求的东西。