Autofac with multiple implementations of the same interface

前端 未结 4 1774
小鲜肉
小鲜肉 2021-02-03 21:17

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?

Mor

相关标签:
4条回答
  • 2021-02-03 21:28

    Not too difficult. You can register concrete types as self and resolve it as you go along. Then your top level message handler (LoggingMessageHandler in your example) can be registered for the interface, which will be used by your TopLevelClass

    Here's what you're looking at (assuming you have a default constructor for FinalHandler)

    var builder = new ContainerBuilder();
    builder.RegisterType<FinalHandler>().AsSelf().SingleInstance();
    builder.Register(c => new DoSomethingMessageHandler(c.Resolve<FinalHandler>())).AsSelf().SingleInstance();
    builder.Register(c => new LoggingMessageHandler(c.Resolve<DoSomethingMessageHandler>())).As<IMessageHandler>().SingleInstance();
    //now finally your top level class - this will automatically pick your LoggingMessageHandler since the others have been registered onto their concreteTypes only
    builder.RegisterType<TopLevelClass>().As<ITopLevelClass>().InstancePerOwned();
    
    0 讨论(0)
  • 2021-02-03 21:34

    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)
        }
      }
    }
    
    0 讨论(0)
  • 2021-02-03 21:44

    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) { ... }
    }
    
    0 讨论(0)
  • 2021-02-03 21:48

    Autofac has Decorators support.

    0 讨论(0)
提交回复
热议问题