将2个Autofac容器合并为一个

本文关键字:一个 合并 2个 Autofac | 更新日期: 2023-09-27 18:18:14

是否有办法将2个autoface容器合并为1个?我的意思是,两个容器中的所有注册都将包含在新容器中或者可以用另一个

升级其中一个例如:

public IContainer Merge(IContainer container1, IContainer container2)
{
     return ???;
}

我试过迭代"container.ComponentRegistry."通过使用containerBuilder注册组件并升级第二个容器,但由于某些原因存在一些冲突

    Autofac.Core.DependencyResolutionException : An exception was thrown while executing a resolve operation. See the InnerException for details. ---> The provided instance has already been used in an activation request. Did you combine a provided instance with non-root/single-instance lifetime/sharing? (See inner exception for details.)
  ----> System.InvalidOperationException : The provided instance has already been used in an activation request. Did you combine a provided instance with non-root/single-instance lifetime/sharing?
   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, ref Object instance)
   at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve(IComponentContext context)
   at Bootstrap.Bootstrapper.CreatePersistentTimerAsyncExecuter(IContainer container)
   at Bootstrap.Bootstrapper.Monitor(IContainer container)
   at Bootstrap.Bootstrapper.Boot(Assembly[] assemblies)
   at Soluto.Telemetry.Processing.Core.IntegrationTests.TelemetryProcessingBootstrapperTests.Boot_With2TelemetryHandlersInAssembly_ResolvesSubscriberWithItsHandlers() in TelemetryProcessingBootstrapperTests.cs: line 88
--InvalidOperationException
   at Autofac.Core.Activators.ProvidedInstance.ProvidedInstanceActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()
   at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)

将2个Autofac容器合并为一个

您可以使用自定义的IRegistrationSource。该接口包含一个RegistrationsFor方法,用于返回特定IServiceIComponentRegistration列表

public class CrossContainerRegistrationSource : IRegistrationSource
{
    public CrossContainerRegistrationSource(IComponentContext componentContext)
    {
        this._componentContext = componentContext;
    }
    private readonly IComponentContext _componentContext;
    public Boolean IsAdapterForIndividualComponents
    {
        get
        {
            return false;
        }
    }
    public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, 
        Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
    {
        return this._componentContext.ComponentRegistry.RegistrationsFor(service);
    }
}

你可以这样使用:

container2.ComponentRegistry.AddRegistrationSource(new CrossContainerRegistrationSource(container1));

但是要小心这个解决方案,当您使用复杂的作用域场景时,它可能会引入问题。

是有可能的。

var existingContainer = new ContainerBuilder();
// Add registrations to existing container.
var newContainerBuilder = new ContainerBuilder();
// Add registrations to new container.
newContainterBuilder.Update(existingContainer);

update方法实质上是将existingContainer的内容合并到newContainerBuilder中。

EDIT -如果使用IContainer

如果您已经将ContainerBuilder构建到IContainer中,ContainerBuilderUpdate方法能够接受IContainer作为输入。但是在这种情况下,已经构建的容器现在将包含所有注册,并且新的ContainerBuilder可以超出作用域。

var builtContainer = existingContainer.Build();
var newContainerBuilder = new ContainerBuilder();
// Add registrations to new container.
newContainterBuilder.Update(builtContainer);

应该注意的是,Update()在较新的Autofac版本中被标记为过时,不应该使用。请参阅https://github.com/autofac/Autofac/issues/811#issuecomment-270246744了解更多说明。

解决这个问题的一些建议如下:

  • 传递ContainerBuilder而不是IContainer
  • 添加注册到子作用域
  • 使用
  • λ
  • <
  • 使用模块/gh>
  • 使用条件注册(4.4.0新功能)
基本上

. .如果可能的话,不要使用2个容器。

谢谢大家的回答,最后,我根据自己的需求做了一些更具体的事情:

public void Merge(this IContainer container1, IContainer container2)
{ 
    var newBuilder = new ContainerBuilder();
    newBuilder.RegisterInstance(container2.Resolve<ISomeService1>()).AsImplementedInterfaces();
    newBuilder.RegisterInstance(container2.Resolve<ISomeService2>()).AsImplementedInterfaces();
    newBuilder.Update(container1);
    return container1;
}