Andrei M Andrei M - 6 days ago 5
C# Question

How to resolve interface based on service where it's passed to

I have an interface.

public interface ISomeInterface {...}


and two implementations (SomeImpl1 and SomeImpl2):

public class SomeImpl1 : ISomeInterface {...}
public class SomeImpl2 : ISomeInterface {...}


I also have two services where I inject ISomeInterface (via contructor):

public class Service1 : IService1
{
public Service1(ISomeInterface someInterface)
{
}
...
}


and

public class Service2 : IService2
{
public Service2(ISomeInterface someInterface)
{
}
...
}


I'm using Autofac as my IoC tool.
The question. How can I configure Autofac registrations so SomeImpl1 will be automatically injected into Service1, and SomeImpl2 will be automatically injected into Service2.

Thank you!

Answer

Autofac supports identification of services by name. Using this, you can register your implementations with a name (using the Named extension method). You can then resolve them by name in the IServiceX registration delegates, using the ResolveNamed extension method. The following code demonstrates this.

var cb = new ContainerBuilder();
cb.Register(c => new SomeImpl1()).Named<ISomeInterface>("impl1");
cb.Register(c => new SomeImpl2()).Named<ISomeInterface>("impl2");
cb.Register(c => new Service1(c.ResolveNamed<ISomeInterface>("impl1"))).As<IService1>();
cb.Register(c => new Service2(c.ResolveNamed<ISomeInterface>("impl2"))).As<IService2>();
var container = cb.Build();

var s1 = container.Resolve<IService1>();//Contains impl1
var s2 = container.Resolve<IService2>();//Contains impl2

Alternative using RegisterType (as opposed to Register)

You can achieve the same result using the RegisterType extension method in combination with WithParameter and ResolvedParameter. This is useful if the constructor taking a named parameter also takes other non-named parameters that you don't care to specify in a registration delegate:

var cb = new ContainerBuilder();
cb.RegisterType<SomeImpl1>().Named<ISomeInterface>("impl1");
cb.RegisterType<SomeImpl2>().Named<ISomeInterface>("impl2");
cb.RegisterType<Service1>().As<IService1>().WithParameter(ResolvedParameter.ForNamed<ISomeInterface>("impl1"));
cb.RegisterType<Service2>().As<IService2>().WithParameter(ResolvedParameter.ForNamed<ISomeInterface>("impl2"));
var container = cb.Build();

var s1 = container.Resolve<IService1>();//Contains impl1
var s2 = container.Resolve<IService2>();//Contains impl2
Comments