Autofac with multiple implementations of the same interface

痞子三分冷 提交于 2019-12-03 10:50:02

问题


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 to TopLevelClass (to fulfill its dependency on IMessageHandler)
  • pass DoSomethingMessageHandler to LoggingMessageHandler (to fulfill its dependency on IMessageHandler)
  • pass LoggingMessageHandler to FinalHandler (to fulfill its dependency on IMessageHandler)

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)?


回答1:


Autofac has Decorators support.




回答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)
    }
  }
}



回答3:


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();


来源:https://stackoverflow.com/questions/22384884/autofac-with-multiple-implementations-of-the-same-interface

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!