Autofac with multiple implementations of the same interface
Solution 1
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) { ... }
}
Solution 2
For anyone else searching, I just ran across this. You can use implicit support for the IEnumerable. I wrote it up for future use.
Basically, you can register assembly types by name (or other criteria) as an IEnumerable which can be consumed later. My favorite part of this approach is that you can keep adding message handlers and as long as you stick to the same criteria, you never have to touch the criteria afterwards.
Autofac Registration:
builder.RegisterAssemblyTypes(typeof (LoggingMessageHandler).Assembly)
.Where(x => x.Name.EndsWith("MessageHandler"))
.AsImplementedInterfaces();
Consuming Class:
public class Foo
{
private readonly IEnumerable<IMessageHandler> _messageHandlers
public Foo(IEnumerable<IMessageHandler> messageHandlers)
{
_messageHandlers = messageHandlers;
}
public void Bar(message)
{
foreach(var handler in _messageHandlers)
{
handler.Handle(message)
}
}
}
Solution 3
Autofac has Decorators support.
kingfleur
I help companies and teams turn legacy code into maintainable software. You can see my work on Twitter, my blog, Careers, LinkedIn, BitBucket and GitHub.
Updated on March 28, 2020Comments
-
kingfleur about 4 years
I'm using Autofac and would like to have multiple implementations of an interface. How can I configure Autofac so to resolve dependencies based on the current type?
More specifically, I have one interface and multiple implementations that should be chained together.
Let me explain (fictitious classes):
public interface IMessageHandler { void Handle(Message message); } public class LoggingMessageHandler : IMessageHandler { private IMessageHandler _messageHandler; public LoggingMessageHandler(IMessageHandler messageHandler) { _messageHandler = messageHandler; } public void Handle(Message message) { // log something _messageHandler.Handle(message); } } public class DoSomethingMessageHandler : IMessageHandler { private IMessageHandler _messageHandler; public DoSomethingMessageHandler (IMessageHandler messageHandler) { _messageHandler = messageHandler; } public void Handle(Message message) { // do something _messageHandler.Handle(message); } }
At the bottom of the chain might be an
IMessageHandler
that doesn't pass the message on to the next one.If I want the following chain:
TopLevelClass -> LoggingMessageHandler -> DoSomethingMessageHandler -> FinalHandler
How can I tell Autofac to
- pass
LoggingMessageHandler
toTopLevelClass
(to fulfill its dependency onIMessageHandler
) - pass
DoSomethingMessageHandler
toLoggingMessageHandler
(to fulfill its dependency onIMessageHandler
) - pass
LoggingMessageHandler
toFinalHandler
(to fulfill its dependency onIMessageHandler
)
Is it even possible (I have read about the implicit support for IEnumerable)? Or will I have to use an extra class in between (a factory or something)?
- pass