Search code examples
c#unity-container

How to merge IUnityContainer with another IUnityContainer


I have a use case where my company moves from a legacy codebase to a new legacy codebase. The combination is unstable, merging the containers would help.

I identified a point where I want to merge the containers and pass a new container to the remaining application.

I have reason to believe that I can overwrite old types without causing problems.

How can I merge an IUnityContainer with another IUnityContainer?

The following is how far my experiments have taken me:

using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Linq;

class ContainerUser
{
    public ContainerUser(IEnumerable<IUnityContainer> chaos)
    {
        IUnityContainer combined = new UnityContainer();
        //is there a highlevel method that can be used?
        //or is a foreach loop the way to go
        foreach (var uc in chaos)
        {
            foreach (var reg in uc.Registrations)
            {
                //combined.Register...???
                //usure what to so here
            }
        }
        //this throws unless combining the conainers works
        combined.Resolve<L1>().Exec();
        combined.Resolve<L2>().Exec();
    }
}

class L1
{
    private L1() { } //private so UnityContainer can not default construct
    public static L1 Get() { return new L1(); } //getter for InjectionFactory
    public void Exec() { Console.WriteLine("L1"); }
}

class L2
{
    private L2() { }
    public static L2 Get() { return new L2(); }
    public void Exec() { Console.WriteLine("L2"); }
}

class Program
{
    public static IEnumerable<T> Randomize<T>(IEnumerable<T> source)
    {
        //randomize to show i do not know a lot about my different containers
        Random rnd = new Random();
        return source.OrderBy<T, int>((item) => rnd.Next());
    }

    static void Main(string[] args)
    {
        //this is the setup, in my usecase these things happe behind the scenes and i can not influence them.
        var ucs = new List<IUnityContainer> { new UnityContainer(), new UnityContainer() };

        ucs[0].RegisterType<L1>(new InjectionFactory(c => L1.Get()));
        ucs[0].Resolve<L1>().Exec(); //proof L1 can resolve

        ucs[1].RegisterType<L2>(new InjectionFactory(c => L2.Get()));
        ucs[1].Resolve<L2>().Exec(); //proof L2 can resolve

        ContainerUser user = new ContainerUser(Randomize(ucs));
    }
}

Solution

  • This is a simple approach how to use extensions to merge containers:

    public class MergeContainerExtension : UnityContainerExtension
    {
        private readonly IUnityContainer[] containers;
    
        public MergeContainerExtension(params IUnityContainer[] containers)
        {
            this.containers = containers;
        }
        protected override void Initialize()
        {
            foreach (var container in containers)
            {
                foreach (var registration in container.Registrations)
                {
                    base.Container.
                        RegisterType(
                        registration.RegisteredType, 
                        registration.MappedToType,
                        registration.Name,
                        registration.LifetimeManager);
                }
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            UnityContainer aContainer = new UnityContainer();
            UnityContainer bContainer = new UnityContainer();
    
    
            UnityContainer container = new UnityContainer();
            MergeContainerExtension mergeExtension = new MergeContainerExtension(aContainer, bContainer);
            container.AddExtension(mergeExtension);
    
    
            var resolve = container.Resolve<IClassA>();
        }
    }