当我希望每个API请求一个实例时,Autofac可以分解为2个单独的实例。
我看到从控制器到命令处理程序的一个实例,以及我的域事件处理程序之一的另一个实例,域处理程序通过属性注入引用调度程序对象。
这里的问题是我没有看到同一个 UserContext 对象实例,在该对象实例中我通过DomainEvent.dispatcher.Raise();
调用的Domain事件处理程序中的Web API控制器进行了注入和修改。>
我遵循与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; }
}
答案 0 :(得分:0)
由于您没有提供a Minimal, Complete, and Verifiable Example,因此很难弄清楚。该示例以及与您的问题相关的所有代码都应在问题中-如果注释中有任何问题,请使用答案更新您的问题。
也就是说,我可以看到您可能陷入的陷阱。
首先,我看到了:
builder
.RegisterType<DomainEventDispatcher>()
.As<IDomainEventDispatcher>()
.InstancePerLifetimeScope();
在ASP.NET/ASP.NET Core中,这通常等同于“每个请求一个实例”,这似乎是您要遵循的方向。但是,这意味着它只能在请求生存期范围内解决。
根容器也是生命周期范围。这就是单例解决的地方。这也是解决单例依赖项的地方。 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
。如果您具有共享的数据连接或需要在容器构建时启动的内容,请将该逻辑分离到可以注册为单例的某种数据提供程序中。这也将避免对每个请求应做的事情进行根级解析。