0

Ich führe eine MVC-App, die eine Reihe von Diensten (die andere Dienste/Helfer/etc aufrufen) enthält. Ich versuche, Parameterwert zu injizieren, die erst zur Laufzeit mit der StrategieInjector Konstruktor Parameterwerte mit Unity

https://www.devtrends.co.uk/blog/how-not-to-do-dependency-injection-the-static-or-singleton-container

Wie in dem Artikel erwähnt skizziert bekannt sind, ist es vorzuziehen, einfach nicht Unity als Servicelocator nutzen - auch, ich würde viel lieber nicht zu einer Instanz des UnityContainer neu zu erstellen (und eine ziemlich hässliche Resolve-Anweisung schreiben) jedes Mal, wenn ich etwas Außergewöhnliches tun möchte (wie inject Laufzeitparameter). Der Artikel ist nun ein paar Jahre alt und Unity unterstützt jetzt TypeFactory und DelegateFactory-Typen, so dass es leicht verbessert werden könnte, aber die Idee, einen Delegaten in den Konstruktor zu injizieren, um Ihre Parameterwerte zu erhalten, entkoppelt den Prozess (Hinweis: Ich bin glücklich, gleich entkoppelte Strategien wie abstrahieren zu einer Fabrik zu diskutieren)

Ich bin fast da mit dem Delegierten-Ansatz in dem Artikel beschrieben, obwohl ich den Delegaten injizieren kann und den Delegierten rufen, um zu bekommen Bei den Werten in einer abstrahierten Klasse unterscheidet sich die Instanz dieser Klasse von der, in der ich die Werte ablege. Daher sind die Werte, die der Delegat-Aufruf sieht, null.

Ich habe versucht, benannte Registrierungen und versuchte verschiedene Lebensdauer Optionen vergebens - in der Regel macht es wenig Unterschied oder Unity nicht die Auflösung und ich bekomme die ... stellen Sie sicher, es gibt parameterlosen Konstruktor ... Ausnahme Nachricht. Beachten Sie auch, dass, wenn ich weg von der Markierung am mit, wie die Parameter zugeordnet und abgerufen werden, fühlen Sie sich frei

Die Essenz meines Codes zu kommentieren ist wie folgt

Bootstrap:

container.RegisterType<IExportDetail, ExportDetail>(); 
container.RegisterType<IExportHelper, ExportHelper>(); 

container.RegisterType<Func<IExportDetail>>(
    new InjectionFactory(c => 
    //new Func<string, IExportDetail>(name => c.Resolve<IExportDetail>(name)))); 
    new Func<IExportDetail>(() => container.Resolve<IExportDetail>()))); 

Abstracted Parameterdeklarationen :

public interface IExportDetail 
{ 
    string Parm1{ get; set; } 
    string Parm2{ get; set; } 
} 
public class ExportDetail : IExportDetail 
{ 
    public string Parm1{ get; set; } 
    public string Parm2{ get; set; } 
} 

Helper/Dienst wird genannt:

public class ExportHelper : IExportHelper 
{ 
    private IExportDetail _service; 
    public ExportHelper(
      Func<IExportDetail> serviceFactory 
     ) 
    { 
     _service = serviceFactory(); 
     _parm1 = _service.Parm1; // <--!!this is null!! 
     _parm2 = _service.Parm2; // <--!!this is null!! 
    } 
} 

Anrufer:

IExportHelper _exportHelper; //<--DI'd 
IExportDetail _exportDetail; //<--DI'd 

_exportDetail.Parm1 = parm1ValueSetAtRuntime; 
_exportDetail.Parm2 = parm2ValueSetAtRuntime; 
return _exportHelper; 
+1

I Denken Sie, Ihr Hauptproblem ist, dass was Sie versuchen zu injizieren ist * n ot ein Service *, es ist ein * Datencontainer *.Dienste enthalten im Allgemeinen * keinen Status * - sie enthalten Geschäftslogik, die ausgeführt werden soll (und können ein Modell wie beispielsweise Ihr ExportDetail übergeben, das keine Schnittstelle benötigt). Sehen Sie [diesen Artikel] (https://cuttingedge.it/blogs/steven/pivot/entry.php?id=97), um den Unterschied zwischen newables (für die Sie einfach das neue Schlüsselwort verwenden sollten) und injectables zu verstehen. – NightOwl888

+0

Danke NightOwl - Ich habe den Artikel in Ihrem Post gelesen - ich kann sehen, dass mein DTO (ExportDetail) nicht über Unty instantiiert werden muss, da es einfach ein DTO ist. Aber für meine Anforderung war der einzige Grund, warum es erstellt wurde zu injizieren - wenn es eine bessere Herangehensweise gibt, kann es leicht entlassen werden, wenn es zum Beispiel durch eine Fabrik für ExportHelper ersetzt werden kann, dann als eine Strategie, der ich folgen kann das - die Frage, die ich stelle, ist, wie das gemacht wird – TerrorBight

+0

Ich habe zahlreiche Beispiele im Internet gesehen - sie fallen in drei Kategorien - (a) ein Service Locator (b) sie registrieren/lösen über den Unity-Container innerhalb des Service-Codes (c) benutze einen Delegierten oder eine Fabrik, um den Code von Unity in den Bootstrap zu injizieren und zu zentralisieren - meine Präferenz ist (c) - aber wie in dem Artikel in meinem ursprünglichen Beitrag, zeigt er nicht, wie/wo er eigentlich zuweisen soll Runtime-Wert (e) – TerrorBight

Antwort

0

Sie können einige Instanzen vom Typ im laufenden Betrieb registrieren, siehe Beispiel unten.

Übrigens ist es sehr seltsam, dass Sie eine Instanz eines Datenobjekts mit Unity registrieren und in helpers \ services einfügen möchten, siehe Kommentar von NightOwl888. (Ich weiß nicht, wie von Antwort auf einen Kommentar antworten)

Bootstrap:

container.RegisterType<Func<string, IExportDetail>>(
    new InjectionFactory(c => 
    new Func<string, IExportDetail>(name => c.Resolve<IExportDetail>(name)))); 

Register Objekt in Laufzeit:

container.RegisterInstance<IExportDetail>("someName", new ExportDetail 
{ 
    Param1 = parm1ValueSetAtRuntime, 
    Param2 = parm2ValueSetAtRuntime 
}); 

Helper:

public ExportHelper(Func<string, IExportDetail> serviceFactory) 
{ 
    IExportDetail exportDetail = serviceFactory("someName"); 
    // Use here exportDetail 
} 
+0

Danke George - das ist ziemlich genau das, was ich bereits als Kompromiss habe - Ich möchte wirklich jedes Mal, wenn ich Constructor-Laufzeitparameter injizieren will, Container-Registeranweisungen innerhalb des Dienstcodes codieren (Gemäß dem im Link des ursprünglichen Posts beschriebenen Design) - Unity bietet die Möglichkeit, die gesamte erforderliche Logik innerhalb des Bootstraps zu zentralisieren – TerrorBight

Verwandte Themen