Reputation: 3112
is there a way i can merge 2 autoface container into 1? I mean that all registrations from both containers will be included in the new one Alternatively it could be upgrade one of them with the other
For example:
public IContainer Merge(IContainer container1, IContainer container2)
{
return ???;
}
I've tried iterating over "container.ComponentRegistry.Registrations" and by using containerBuilder registering components and upgrading the second container but for some reason there were some conflicts
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)
Any Ideas ?
Upvotes: 4
Views: 3043
Reputation: 41
It should be noted that Update()
is marked obsolete in newer versions of Autofac and should not be used. See https://github.com/autofac/Autofac/issues/811#issuecomment-270246744 for more clarification.
Some of the recommendations listed to get around this issue is:
Basically.. don't end up with 2 containers if possible.
Upvotes: 1
Reputation: 3112
Thanks for all the answers guys, eventually i did something more specific for my needs:
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;
}
Upvotes: 1
Reputation: 892
Yes it is possible.
var existingContainer = new ContainerBuilder();
// Add registrations to existing container.
var newContainerBuilder = new ContainerBuilder();
// Add registrations to new container.
newContainterBuilder.Update(existingContainer);
The update
method essentially merges the contents of the existingContainer
into the newContainerBuilder
.
If you have already built your ContainerBuilder
into an IContainer
the Update
method of the ContainerBuilder
is able to accept an IContainer
as input. But in this case the already built container will now contain all the registrations and the new ContainerBuilder
can go out of scope.
var builtContainer = existingContainer.Build();
var newContainerBuilder = new ContainerBuilder();
// Add registrations to new container.
newContainterBuilder.Update(builtContainer);
Upvotes: 1
Reputation: 16192
You can use a custom IRegistrationSource
. This interface contains a RegistrationsFor
method that return a list of IComponentRegistration
for a specific IService
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);
}
}
You can use it like this :
container2.ComponentRegistry.AddRegistrationSource(new CrossContainerRegistrationSource(container1));
But be careful with this solution it may introduce issue when you use complex scope scenario.
Upvotes: 4