缓存依赖项,还是在注入时复制它们?



我有一些Autofac初始化的配置对象。它们的负载非常重(读取配置文件,对其进行反序列化,验证一些内容,映射匹配的POCO对象……)。
但是性能很好,因为注册对象被声明为.SingleInstance(),所以它只加载一次,第一次在某处注入,之后总是使用相同的实例。

builder.Register(c => _settingsReader.LoadSection(thing)) // Read and map object
.OnActivated(t =>
{
// Do some checks on it to see if settings appear to be correct
})
.As(settingInterface)
.SingleInstance();

但是,这些对象可以在以后被修改(有意或无意),并且由于它们是单例,如果发生这种情况,整个应用程序将受到影响。

能够更新初始单例本身(全局覆盖已定义的设置)和更新本地副本(更改已注入设置类的对象的行为,但不是整个应用程序)的能力也会很有趣。

我考虑了两种可能性:

  • 要求autoface注入"copy"的对象,而不是相同的实例,但我不认为有这样的"缓存/复制";我将失去操作单例的能力,或者
  • 使用Automapper在对象被注入时进行深度复制,并将副本存储在依赖对象中,而不是原始对象中。我对automapper很满意(并且对象非常轻,因此性能不会成为问题),但是为每个注入的属性添加副本将负担我的Autofac配置或我的对象本身,这取决于我放置"复制此对象"的位置。代码。

要使用Automapper的想法,我必须这样做:

builder.RegisterType<MyConsumingClass>()
.WithParameter(
new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(IMySettingClass),
(pi, ctx) =>
{
var mapper = ctx.Resolve<Mapper>();
return mapper.Map<ConcreteSettingClass>(ctx.Resolve<IMySettingClass>());
}))
.As<IMyConsumingClass>();

而不是

builder.RegisterType<MyConsumingClass>().As<IMyConsumingClass>();

(前面的代码没有经过测试,这里只是作为示例)

如果你能给我一些最好的建议,我将不胜感激。

正如在评论中所说,由于缺乏其他建议,我最终保留了自己最初的方法,并在创建消费类的新实例时使用Automapper克隆我的设置对象。下面是一个Service和它的设置对象的例子。如果你的"设置"对象在其属性中有类,记住也要克隆它们,否则你只会得到初始单例的引用副本!为了避免这个陷阱,你也可以使用一个真正的"克隆库"。

public class ServiceFacadeModule
: Module
{
protected override void Load(ContainerBuilder builder)
{
// Modifying the settings on the service instance itself should NOT affect global setting object. To achieve this, settings classes are copied when initializing new service instances
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ServiceSettings, ServiceSettings>();
});
var mapper = new Mapper(config);
builder.RegisterType<ServiceDAO>()
.WithParameter(
new ResolvedParameter(
(pi, _) => pi.ParameterType == typeof(ISettings),
(_, ctx) => mapper.Map<ServiceSettings>(ctx.Resolve<ISettings>())))
.As<IServiceDAO>()
.InstancePerLifetimeScope();
}
}

最新更新