AutoFac中每个模块的LifetimeScope

时间:2017-06-30 14:10:05

标签: c# autofac

我创建了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");

0 个答案:

没有答案