wake-up-neo.com

Autofac mit mehreren Implementierungen derselben Schnittstelle

Ich verwende Autofac und möchte mehrere Implementierungen einer Schnittstelle haben. Wie kann ich Autofac so konfigurieren, dass Abhängigkeiten basierend auf dem aktuellen Typ aufgelöst werden?

Genauer gesagt, ich habe eine Schnittstelle und mehrere Implementierungen, die miteinander verkettet werden sollten.

Lassen Sie mich erklären (fiktive Klassen):

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

Am Ende der Kette befindet sich möglicherweise eine IMessageHandler, die die Nachricht nicht an die nächste weiterleitet.

Wenn ich folgende Kette will:

TopLevelClass -> LoggingMessageHandler -> DoSomethingMessageHandler -> FinalHandler

Wie kann ich Autofac mitteilen? 

  • LoggingMessageHandler an TopLevelClass übergeben (um seine Abhängigkeit von IMessageHandler zu erfüllen)
  • DoSomethingMessageHandler an LoggingMessageHandler übergeben (um seine Abhängigkeit von IMessageHandler zu erfüllen)
  • LoggingMessageHandler an FinalHandler übergeben (um seine Abhängigkeit von IMessageHandler zu erfüllen)

Ist es überhaupt möglich (ich habe über die implizite Unterstützung für IEnumerable gelesen)? Oder muss ich zwischendurch eine zusätzliche Klasse (eine Fabrik oder etwas anderes) verwenden?

20
Peter

Autofac hat Dekorateure Unterstützung.

6
Jim Bolla

Für alle anderen Suchenden bin ich auf dieses Thema gestoßen. Sie können die implizite Unterstützung für IEnumerable verwenden. Ich schrieb es für die zukünftige Verwendung auf .

Grundsätzlich können Sie Assembly-Typen nach Namen (oder anderen Kriterien) als IEnumerable registrieren, die später verwendet werden können. Mein Lieblingsteil dieses Ansatzes ist, dass Sie fortwährend Message-Handler hinzufügen können. Solange Sie sich an dieselben Kriterien halten, müssen Sie die Kriterien danach nie berühren.

Autofac-Registrierung:

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

Verbrauchsklasse:

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)
    }
  }
}
17
Kevin R.

Nicht zu schwer Sie können konkrete Typen als selbst registrieren und im weiteren Verlauf auflösen. Dann kann Ihr Top-Level-Message-Handler (in Ihrem Beispiel LoggingMessageHandler) für die Schnittstelle registriert werden, die von Ihrer TopLevelClass verwendet wird

Hier sehen Sie, was Sie gerade betrachten (vorausgesetzt, Sie haben einen Standardkonstruktor für 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
arviman