5

Ich verwende das Simple Injector IoC-Framework, und ich möchte in der Lage sein, die Abhängigkeitsregistrierung zur Laufzeit zu ändern. Zum Beispiel habe ich zwei Implementierungen, A und B, der Schnittstelle I. Die Implementierung A wird beim Start der App registriert, aber abhängig von einem Flag, das sich während der Laufzeit ändern kann, möchte ich die Implementierung wechseln. Wir tun dies derzeit das OnActionExecuting Ereignis unserer BaseController, die alle unsere Controller erben. Hier ist der Beispielcode von dem, was ich versuche zu tun.Wie ändert man die Abhängigkeitsregistrierung zur Laufzeit mit einem einfachen Injektor?

protected override void OnActionExecuting(
    ActionExecutingContext filterContext) 
{ 
    if (IsRuntimeFlag) 
    { 
     // check current implementation type and 
     // change implementation to A 
    } 
    else 
    { 
     // check current implementation type and 
     // change implementation to B 
    } 

    base.OnActionExecuting(filterContext); 
} 

Vielen Dank im Voraus für Ihre Hilfe.

+1

Ich würde empfehlen, eine Fabrik mit einem Strategie-Muster zu kombinieren, anstatt einen DI-Container dafür zu verwenden. Verwenden Sie den Container, um Ihr Objektdiagramm frühzeitig aufzulösen. Siehe [Composition Root] (http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx). – TrueWill

+0

Müssen Sie das manuell tun? Wie wäre es mit einem IOC Container Framework? –

Antwort

9

Bei IsRuntimeFlag ist ein Konfigurationswert (also nicht während der Lebensdauer der Anwendung ändern kann), können Sie die Registrierung vornehmen wie folgt:

if (IsRuntimeFlag) 
{ 
    container.Register<I, A>(); 
} 
else 
{ 
    container.Register<I, B>(); 
} 

oder gleich:

container.Register(typeof(I), IsRuntimeFlag ? typeof(A) : typeof(B)); 

Bei Der Wert kann sich während der Lebensdauer der Anwendung ändern. Ein Proxy oder composite, der die Verteilung an die richtige Instanz übernimmt, ist die richtige Lösung:

public sealed class RuntimeFlagIComposite : I 
{ 
    private readonly A a; 
    private readonly B b; 

    public RuntimeFlagIComposite(A a, B b) { 
     this.a = a; 
     this.b = b; 
    } 

    void I.Method() => this.Instance.Method(); 

    private I Instance => IsRuntimeFlag ? this.a : this.b; 
} 

Da der Verbund hängt direkt von A und B, können Sie es einfach wie folgt registrieren:

container.Register<I, RuntimeFlagIComposite>(); 

Wenn A oder B haben eine andere Lebensdauer als transiente (eine neue Instanz für jede Anfrage), Sie sollte sie auch registrieren. Zum Beispiel:

container.Register<A>(Lifestyle.Singleton); 
container.Register<B>(Lifestyle.Scoped); 

Sie können auch Ihre Composite hängen von der I Abstraktion selbst anstelle der konkreten A und B Implementierungen lassen:

public class RuntimeFlagIComposite : I 
{ 
    private I a; 
    private I b; 

    public RuntimeFlagIComposite(I a, I b) 
    { 
     this.a = a; 
     this.b = b; 
    } 
} 

Je nach I Abstraktion dieser Klasse flexibler und macht testbar. Es bedeutet jedoch, dass Sie es ein wenig anders registrieren müssen:

+0

Vielen Dank für Ihre Antwort, jedoch ist diese Flagge zum Zeitpunkt der Containerregistrierung unbekannt und kann sich während der gesamten Lebensdauer der Anwendung ändern. Ich denke, ich kann eine globale Flagge setzen und sie später während der Anwendung ändern, aber ich denke nicht, dass es ein sauberer Ansatz ist. Bei näherem Hinsehen denke ich, dass das zusammengesetzte Muster in diesem Fall funktionieren könnte. Danke nochmal für deine Hilfe. – Will

+0

Hallo Steven, Ich frage mich nur, ob Sie noch andere Ideen haben. Bei dem Versuch, dies zu implementieren, erkannte ich, dass die Flagge auch Dinge in der Web-App-Schicht, Cookies Werte spezifisch, im Gegensatz zu der Service-Schicht, wo die Zusammensetzung wäre. Daher hätte der Verbund keinen Zugriff auf die Flagge. Nochmals vielen Dank im Voraus. – Will

+1

Ich denke, Sie haben Ihre eigene Frage beantwortet.Wenn die Zusammensetzung von UI-spezifischen Dingen abhängt, sollte sie in der UI-Ebene definiert werden. Da die Schnittstelle in einer unteren Ebene definiert ist, ist es absolut in Ordnung, sie in Ihrer UI-Ebene zu definieren (oder Sie könnten sie sogar in Ihren Kompositionswurzel einfügen). – Steven

Verwandte Themen