Autofac单例装饰器多次构建问题

3

我正在尝试为一些服务创建一个简单的内存缓存机制。我使用装饰者模式,创建了一个缓存版本的服务来装饰它的具体实现。 通过使用Autofac,我将注册缓存装饰器为SingleInstance()以确保数据留在内存中。

 builder.RegisterDecorator<IBackendOperatorServiceProxy>(
      (c, inner) =>  new CachedBackendOperatorServiceProxy(inner), 
      fromKey: "BackendOperatorService")
      .SingleInstance();

我会将具体实现注册为

 builder.RegisterType<BackendOperatorServiceProxy>().Named<IBackendOperatorServiceProxy>("BackendOperatorService");

我遇到的问题是,在WebApi控制器中解析时,这个单例装饰器总是被重新创建(每个请求一次)。
我已经(希望我已经)正确地为autofac设置了owin管道(实际上,服务被注入到由控制器调用的BL类中)。
我真的无法理解这样一个问题的可能原因。我在不同的项目中多次使用SingleInstance(),而且总是没有问题。
为了进一步“调查”这个问题,我还创建了一个假类,将其注册为单例,并将其注入到与装饰器相同的控制器中。它像预期的那样工作,只创建了一个假类的实例。 为了完整起见,我已将此虚拟类注册为:
builder.Register<Foo>(c => new Foo(c.ResolveNamed<IBackendOperatorServiceProxy>("BackendOperatorService"))).AsImplementedInterfaces().SingleInstance();

以下是Cached (Decorator)服务的构造函数:

public CachedBackendOperatorServiceProxy(IBackendOperatorServiceProxy decoratedServiceImplementation)
{
  _decoratedServiceImplementation = decoratedServiceImplementation ?? throw new ArgumentNullException(nameof(decoratedServiceImplementation));
  _cachedElements = new Dictionary<string, CachedOperatorDto>();
}

装饰器和单例模式有什么问题或者我忽略了什么吗?


1
如果您手动注册装饰器,而不使用RegisterDecorator,那么是否会按预期工作? - Evk
是的。通过手动注册装饰器似乎可以按预期工作。因此,autofac 存在某种问题。 无论如何,这是我注册服务的方式:builder.Register(c => new CachedBackendOperatorServiceProxy( c.ResolveNamed<IBackendOperatorServiceProxy>("BackendOperatorService"))).AsImplementedInterfaces() .SingleInstance(); - Gnegno
顺便问一下,您知道在我之前的评论中注册和使用RegisterDecorator有什么区别吗? - Gnegno
1
本文阐述了 https://nblumhardt.com/2011/01/decorator-support-in-autofac-2-4/ 中的差异。也许这就是它不能作为单例工作的原因(因为它会包装所有使用相同键注册的实例,而不仅仅是一个)。 - Evk
谢谢,那很有道理。在我的情况下,我只需要一对一的“装饰”关系。所以我会使用老式的手动注册。 - Gnegno
1
是的,我也这么认为。我尝试过多次使用装饰器\适配器,但每次都会出现一些问题(我记得我在这里回答了几个与此类问题相关的问题),所以我也只是使用老式的手动注册。 - Evk
1个回答

0
感谢 Evk,最简单的解决方案是只使用“手动”装饰器注册,因为 RegisterDecorator(如评论中提供的链接所述)应该用于需要装饰多个实现而不是像我尝试做的那样仅装饰一个实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接