Search code examples
c#inversion-of-controlautofacconstructor-injection

How to inject constructor which has two times the same interface with Autofac


I want to replace my Unity IoC in my Xamarin 3.2 App with Autofac IoC. Because I haven't any experience with Autofac and the documentation doesn't explain what I need, I hope anyone can help me.

I don't know, how I have to configure the constructor injection, if the class gets two interfaces of the same type in the constructor, but with different implementations. My example shows two repositories and a facade. I want to give both repositories (same interface type) the facade constructor.

What I have

public class HostManager : IHost
    {
           public HostManager()
           {
           }
    }
    public class CustomerRepository : IRepository
    {
           public CustomerRepository(Context context)
           {
           }
    }
    public class AgentRepository : IRepository
    {
           public AgentRepository(Context context)
           {
           }
    }
    public class ToDoFacade : IFacade
    {
    	public ToDoFacade(IHost host, IRepository agentRepository, IRepository customerRepository)
    	{
    	}
    }

    // IoC registration

    public class Registry
    {
        public Registry()
        {
    	var builder = new ContainerBuilder();
    	builder.RegisterType<HostManager>().As<IHost>().SingleInstance();
    	builder.RegisterType<AgentRepository>().As<IRepository>().PreserveExistingDefaults();
    	builder.RegisterType<CustomerRepository>().Named<IRepository>("Customer");

// How can I continue here?
    	builder.RegisterType<ToDoFacade>().As<IFacade>().UsingConstructor(...);
        }
    }

Do you have an idea for me, how I can solve it? Links to resources are also welcome.

Best Tino


Solution

  • You can use ResolvedParameter to inject certain named registrations to your class. Here is an example with test:

    [Test]
    public void InjectCertainRegistration()
    {
        // Arrange 
        var registry = new Registry();
    
        // Act
        var facade = registry.GetFacade();
    
        // Assert
        Assert.IsInstanceOf<AgentRepository>(facade.AgentRepository);
        Assert.IsInstanceOf<CustomerRepository>(facade.CustomerRepository);
    }
    
    // IoC registration
    public class Registry
    {
        private readonly IContainer _root;
    
        public Registry()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<HostManager>().As<IHost>().SingleInstance();
            builder.RegisterType<AgentRepository>().As<IRepository>().Named<IRepository>("Agent").PreserveExistingDefaults();
            builder.RegisterType<CustomerRepository>().Named<IRepository>("Customer");
    
            builder.RegisterType<ToDoFacade>().As<IFacade>()
                .WithParameter(new ResolvedParameter((p, ctx) => p.Name == "agentRepository",
                    (p, ctx) => ctx.ResolveNamed<IRepository>("Agent")))
                .WithParameter(new ResolvedParameter((p, ctx) => p.Name == "customerRepository",
                    (p, ctx) => ctx.ResolveNamed<IRepository>("Customer")));
    
            _root = builder.Build();
        }
    
        public IFacade GetFacade()
        {
            return _root.Resolve<IFacade>();
        }
    }
    
    public class ToDoFacade : IFacade
    {
        /// <summary>
        /// Just for testing
        /// </summary>
        public IRepository AgentRepository { get; }
    
        /// <summary>
        /// Just for testing
        /// </summary>
        public IRepository CustomerRepository { get; }
    
        public ToDoFacade(IHost host, IRepository agentRepository, IRepository customerRepository)
        {
            AgentRepository = agentRepository;
            CustomerRepository = customerRepository;
        }
    }
    
    public class CustomerRepository : IRepository
    {
        public CustomerRepository()
        {
        }
    }
    public class AgentRepository : IRepository
    {
        public AgentRepository()
        {
        }
    }
    
    public interface IFacade
    {
        /// <summary>
        /// Just for testing
        /// </summary>
        IRepository AgentRepository { get; }
    
        /// <summary>
        /// Just for testing
        /// </summary>
        IRepository CustomerRepository { get; }
    }
    
    public class HostManager : IHost
    {
        public HostManager()
        {
        }
    }
    
    public interface IHost { }
    
    public interface IRepository { }
    

    I have modified your example a little bit. Method Registry.GetFacade() returns IFacade instance from container. Also I have added repository properties to make sure about their types in tests. Constructor of repositories became parameterless just to simplify the example. Hope it helps.