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
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.