2014-03-13 13 views
13

Ich benutze 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?Autofac mit mehreren Implementierungen der gleichen Schnittstelle

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

Lassen Sie mich (fiktive Klassen) erklären:

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 unteren Ende der Kette könnte ein IMessageHandler sein, die nicht die Nachricht an die nächste hindurchgeht.

Wenn ich die folgende Kette:

TopLevelClass -> LoggingMessageHandler -> DoSomethingMessageHandler -> FinalHandler 

Wie kann ich sagen Autofac zu

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

Ist es überhaupt möglich (ich habe über die implicit support for IEnumerable lesen)? Oder muss ich eine Extraklasse dazwischen verwenden (eine Fabrik oder etwas)?

+0

Was Sie beschreiben, ist das [Decorator Pattern] (https://en.wikipedia.org/wiki/Decorator_pattern). Ihr 'LoggingMessageHandler' ist ein Dekorator. – Steven

Antwort

8

Für alle anderen, die ich gesucht habe, bin ich einfach darüber gestolpert. Sie können die implizite Unterstützung für IEnumerable verwenden. I wrote it up for future use.

Grundsätzlich können Sie Assembly-Typen nach Name (oder anderen Kriterien) als IEnumerable registrieren, die später konsumiert werden können. Mein Lieblingsteil dieses Ansatzes ist, dass Sie weiterhin Nachrichtenhandler hinzufügen können und solange Sie sich an die gleichen Kriterien halten, müssen Sie die Kriterien danach nie mehr berühren.

Autofac Anmeldung:

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

Konsumieren Klasse:

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

nicht allzu schwierig. Sie können konkrete Typen als selbst registrieren und lösen, während Sie weitermachen. Dann ist Ihr Top-Level-Nachrichten-Handler (LoggingMessageHandler in Ihrem Beispiel) für die Schnittstelle registriert werden, die von Ihrem TopLevelClass verwendet werden

Hier ist, was Sie suchen auf (vorausgesetzt, Sie einen Standardkonstruktor für FinalHandler haben)

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