具有相同接口的多个实现的Autofac

时间:2014-03-13 16:26:27

标签: c# dependency-injection inversion-of-control autofac

我正在使用Autofac,并希望有多个接口实现。如何配置Autofac以便根据当前类型解析依赖关系?

更具体地说,我有一个接口和多个应该链接在一起的实现。

让我解释一下(虚拟课程):

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

链的底部可能是IMessageHandler,它不会将消息传递给下一个消息。

如果我想要以下链:

TopLevelClass -> LoggingMessageHandler -> DoSomethingMessageHandler -> FinalHandler

如何告知Autofac

  • LoggingMessageHandler传递给TopLevelClass(以实现对IMessageHandler的依赖)
  • DoSomethingMessageHandler传递给LoggingMessageHandler(以实现对IMessageHandler的依赖)
  • LoggingMessageHandler传递给FinalHandler(以实现对IMessageHandler的依赖)

是否可能(我已阅读implicit support for IEnumerable)?或者我是否必须在中间使用额外的课程(工厂或其他)?

4 个答案:

答案 0 :(得分:17)

对于任何其他搜索,我只是碰到了这个。您可以对IEnumerable使用隐式支持。 I wrote it up for future use

基本上,您可以按名称(或其他条件)将程序集类型注册为IEnumerable,以后可以使用。我最喜欢的方法是你可以继续添加消息处理程序,只要你坚持相同的标准,你就不必再接触标准了。

Autofac注册:

builder.RegisterAssemblyTypes(typeof (LoggingMessageHandler).Assembly)
  .Where(x => x.Name.EndsWith("MessageHandler"))
  .AsImplementedInterfaces();

消费类:

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

答案 1 :(得分:6)

Autofac支持Decorators

答案 2 :(得分:2)

此处有4个选项:https://autofaccn.readthedocs.io/en/latest/faq/select-by-context.html

选项1:重新设计界面

ILoggingMessageHandler , IDoSomethingMessageHandler 

选项2:更改注册

builder.Register(ctx => new FinalHandler(ctx.Resolve<LoggingMessageHandler >()));
or
builder.Register(ctx => new FinalHandler(ctx.Resolve<IDoSomethingMessageHandler >()));

选项3:使用密钥服务

builder.RegisterType<FinalHandler>()
           .WithParameter(
             new ResolvedParameter(
               (pi, ctx) => pi.ParameterType == typeof(IMessageHandler),
               (pi, ctx) => ctx.ResolveKeyed<ISender>("something")));

选项4:使用元数据

public class FinalHandler
{
  public FinalHandler([WithMetadata("sendBy", "something")] IMessageHandler messageHandler) { ... }
}

答案 3 :(得分:0)

不太难。您可以将具体类型注册为self并在进行时解决它。然后可以为接口注册顶级消息处理程序(在您的示例中为LoggingMessageHandler),TopLevelClass将使用该接口

以下是您正在查看的内容(假设您有一个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();
相关问题