wake-up-neo.com

Kann ich Konstruktorparameter an die Resolve () -Methode von Unity übergeben?

Ich verwende Microsoft Unity für die Abhängigkeitsinjektion und möchte Folgendes tun:

IDataContext context = _unityContainer.Resolve<IDataContext>();
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context

IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);

RepositoryA und RepositoryB haben beide einen Konstruktor, der einen IDataContext -Parameter akzeptiert, und ich möchte, dass Unity das Repository mit dem Kontext initialisiert, den ich ihm übergebe. Beachten Sie auch, dass IDataContext nicht bei Unity registriert ist (ich möchte keine 3 Instanzen von IDataContext).

85
NotDan

Ab heute haben sie diese Funktionalität hinzugefügt:

Es ist in letzter Zeit hier:

http://unity.codeplex.com/SourceControl/changeset/view/33899

Diskussion dazu hier:

http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434

Beispiel:

container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"
70
Exist

<2 Cent>

Was ist, wenn Sie sich später für einen anderen Dienst entscheiden, der mehr oder weniger als nur den Kontext erfordert?

Das Problem bei Konstruktorparametern und IoC besteht darin, dass die Parameter letztendlich an den verwendeten konkreten Typ gebunden sind, anstatt Teil des Vertrags zu sein, den die Serviceschnittstelle definiert.

Mein Vorschlag wäre, dass Sie entweder auch den Kontext auflösen, und ich glaube, dass Unity eine Möglichkeit haben sollte, das Erstellen von drei Instanzen zu vermeiden, oder dass Sie einen Factory-Service in Betracht ziehen sollten, mit dem Sie das Objekt erstellen können.

Was ist zum Beispiel, wenn Sie später beschließen, ein Repository zu erstellen, das sich überhaupt nicht auf eine herkömmliche Datenbank stützt, sondern stattdessen eine XML-Datei verwendet, um Dummy-Daten für den Test zu erstellen? Wie würden Sie den XML-Inhalt diesem Konstruktor zuführen?

IoC basiert auf der Entkopplung von Code. Indem Sie den Typ und die Semantik der Argumente mit den konkreten Typen verknüpfen, haben Sie die Entkopplung wirklich nicht richtig durchgeführt. Es besteht immer noch eine Abhängigkeit.

Msgstr "Dieser Code kann mit jeder Art von Repository kommunizieren, solange er diese Schnittstelle implementiert .... Oh, und verwendet einen Datenkontext.".

Jetzt weiß ich, dass andere IoC-Container dies unterstützen, und ich hatte es auch in meiner ersten Version, aber meiner Meinung nach gehört es nicht zum Auflösungsschritt.

</ 2 Cent>

Danke Jungs ... meine ist ähnlich wie der Beitrag von "Exist". Siehe unten:

        IUnityContainer container = new UnityContainer();
        container.LoadConfiguration();

        _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
        {
            new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
        });
7
Kwex

Sie können InjectionConstructor/InjectionProperty/InjectionMethod in Abhängigkeit von Ihrer Injection-Architektur im ResolvedParameter <T> ("name") verwenden, um eine Instanz eines vorregistrierten Objekts im Container abzurufen.

In Ihrem Fall muss dieses Objekt mit einem Namen registriert sein und für dieselbe Versicherung benötigen Sie ContainerControlledLifeTimeManager () wie den LifeTimeManager.

_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager());
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB");

  var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB")));
5
Trecenti

Die sehr kurze Antwort lautet: nein. Unity hat derzeit keine Möglichkeit, Parameter an den Konstruktor zu übergeben, die nicht konstant oder injiziert sind und die ich gefunden habe. IMHO, das ist das Größte, was fehlt, aber ich denke, es ist eher beabsichtigt als unterlassen.

Wie Jeff Fritz bemerkt, könnten Sie theoretisch einen benutzerdefinierten Lifetime-Manager erstellen, der weiß, welche Kontextinstanz in verschiedene Typen zu injizieren ist. Dies ist jedoch eine Ebene der Hardcodierung, die den Zweck der Verwendung von Unity oder DI an erster Stelle zu umgehen scheint.

Sie können einen kleinen Schritt von der vollständigen DI zurückgehen und Ihre Repository-Implementierungen für die Einrichtung ihrer eigenen Datenkontexte verantwortlich machen. Der Kontext Instanz kann immer noch aus dem Container aufgelöst werden, aber die Logik für die Entscheidung, welcher verwendet werden soll, muss in die Implementierung des Repositorys einfließen. Es ist sicherlich nicht so rein, aber es würde das Problem loswerden.

3
Neil Hewitt

Eine andere Alternative, die Sie verwenden könnten (Sie wissen nicht genau, ob dies eine gute Vorgehensweise ist oder nicht), besteht darin, zwei Container zu erstellen und für jeden Container eine Instanz zu registrieren:

IDataContext context = _unityContainer.Resolve<IDataContext>();
_unityContainer.RegisterInstance(context);
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context


//declare _unityContainer2
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance
_unityContainer2.RegisterInstance(context2);
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance

hoffe das hilft auch

1
Samuel Carrijo

NotDan, ich glaube, Sie haben Ihre eigene Frage in Kommentaren an lassevk beantwortet.

Zuerst würde ich einen LifetimeManager verwenden, um den Lebenszyklus und die Anzahl der von Unity erstellten Instanzen von IDataContext zu verwalten.
http://msdn.Microsoft.com/en-us/library/cc440953.aspx

Es hört sich so an, als würde das Objekt ContainerControlledLifetimeManager Ihnen die Instanzverwaltung geben, die Sie benötigen. Mit diesem LifetimeManager sollte Unity allen Objekten, für die eine IDataContext-Abhängigkeit erforderlich ist, dieselbe Instanz von IDataContext hinzufügen.

0
Jeff Fritz