Autofac with multiple implementations of the same interface
Autofac implicitly supports this by default via the use of IEnumerable<T>
. Instead of having your depending class's constructor take in a single instance of T
, you make it take in an instance of IEnumerable<T>
that will contain every T
registered:
public interface IMessageHandler
{
void HandleMessage(Message m);
}
public class MessageProcessor
{
private IEnumerable<IMessageHandler> _handlers;
public MessageProcessor(IEnumerable<IMessageHandler> handlers)
{
_handlers = handlers;
}
public void ProcessMessage(Message m)
{
foreach (var handler in _handlers)
{
handler.HandleMessage(m);
}
}
}
Then in your registration, simply add multiple implementations of T
:
var builder = new ContainerBuilder();
builder.RegisterType<FirstHandler>().As<IMessageHandler>();
builder.RegisterType<SecondHandler>().As<IMessageHandler>();
builder.RegisterType<ThirdHandler>().As<IMessageHandler>();
builder.RegisterType<MessageProcessor>();
When MessageProcessor
is instantiated, the IEnumerable
it receives will contain three items as per the above registrations against IMessageHandler
.
You can read more about this on my blog.
4 options here: https://autofaccn.readthedocs.io/en/latest/faq/select-by-context.html
Option 1: Redesign Your Interfaces
ILoggingMessageHandler , IDoSomethingMessageHandler
Option 2: Change the Registrations
builder.Register(ctx => new FinalHandler(ctx.Resolve<LoggingMessageHandler >()));
or
builder.Register(ctx => new FinalHandler(ctx.Resolve<IDoSomethingMessageHandler >()));
Option 3: Use Keyed Services
builder.RegisterType<FinalHandler>()
.WithParameter(
new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(IMessageHandler),
(pi, ctx) => ctx.ResolveKeyed<ISender>("something")));
Option 4: Use Metadata
public class FinalHandler
{
public FinalHandler([WithMetadata("sendBy", "something")] IMessageHandler messageHandler) { ... }
}
Autofac has Decorators support.