我创建了GitHub issue,但我应该先在这里问一下,所以这是我的问题:
情况
我们的解决方案中有一些常见的接口,例如IWorker
及其实现Worker
。
需要配置此类。
public class Worker : IWorker
{
private string selectedTag;
public string DoWork()
{
return this.selectedTag;
}
public void Configure(string tag)
{
this.selectedTag = tag;
}
}
我们在AutoFacs Modules的帮助下使用类似架构的插件。 因此,模块会不时地注册和配置“工人”:
builder.RegisterType<ViewModel1>();
builder.RegisterType<Worker>()
.OnActivating(x => x.Instance.Configure("Worker for ViewModel1"))
.AsImplementedInterfaces();
类似的代码可以在另一个模块中找到,但有另一个配置。
问题
这个问题非常明显。一个模块的注册覆盖另一个模块,每次容器解析IWorker
时,它只使用最后一个配置。
解决方案
我在您的文档中找到的一个解决方案是使用Keyed函数。有了这个,我就可以用特定标签键入每个工人。但我的问题是我必须在后续类中使用KeyFilterAttribute
,这在我的情况下是不希望的,因为我们想要最小化容器依赖性我只想在我的模块类中使用Autofac。
可能的解决方案?
我认为更好的解决方案就像基于模块的生命周期范围,因此我可以配置容器以使用每个模块的注册。
builder.RegisterType<Worker>()
.OnActivating(x => x.Instance.Configure("Worker for ViewModel1"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
如果我现在注册一个模块,我想告诉容器它应该为这个模块创建一个新的范围,如:
builder.RegisterModule<Module1>("NewLifetimeScope");
你怎么看?这可能吗?还是我错过了另一种解决方案?
请注意,最后我使用Prism和autofac,因此我无法手动启动新的LifetimeScope。 我附上了一个小repo Solution的单元测试,看看我需要什么。
使用密钥更新解决方案:
我从link读了Travis Illig。在文档中,您可以使用通过密钥注册的服务的另一种方式(不是KeyFilterAttribute
)。
builder.RegisterType<ViewModel1>()
.WithParameter(
new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(IWorker),
(pi, ctx) => ctx.ResolveKeyed<IWorker>("Worker1")));
builder.RegisterType<Worker>()
.OnActivating(x => x.Instance.Configure("Worker for ViewModel1"))
.Keyed<IWorker>("Worker1");
使用此解决方案,我可以在我的模块中配置依赖项。我觉得我很好。
更新
为了提高模块的可读性,我添加了一个扩展方法WithKeyedParameter
,它封装了注册。
public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TStyle> WithKeyedParameter<TLimit, TReflectionActivatorData, TStyle>(this IRegistrationBuilder<TLimit, TReflectionActivatorData, TStyle> registration, Type paramType, object key) where TReflectionActivatorData : ReflectionActivatorData
{
return registration.WithParameter(new ResolvedParameter((pi, ctx) => pi.ParameterType == paramType, (pi, ctx) => ctx.ResolveKeyed(key, paramType)));
}
这样注册就像:
builder.RegisterType<ViewModel1>().WithKeyedParameter(typeof(IWorker), "Worker1");