it-swarm-eu.dev

Czy mogę przekazać parametry konstruktora do metody Unity's Resolve ()?

Używam Microsoft Unity do wstrzykiwania zależności i chcę zrobić coś takiego:

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 i RepositoryB mają konstruktor, który przyjmuje parametr IDataContext, i chcę, aby Unity zainicjowało repozytorium w kontekście, który przekazuję. Zauważ też, że IDataContext nie jest zarejestrowana w Unity (nie chcę 3 instancji IDataContext).

85
NotDan

Na dzień dzisiejszy dodali tę funkcjonalność:

Jest w najnowszej kropce tutaj:

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

Dyskusja na ten temat tutaj:

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

Przykład:

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

<2 centy>

Co jeśli później zdecydujesz się skorzystać z innej usługi, która wymaga więcej lub mniej niż kontekstu?

Problem z parametrami konstruktora i IoC polega na tym, że parametry są ostatecznie powiązane z używanym konkretnym typem, w przeciwieństwie do bycia częścią kontraktu definiowanego przez interfejs usługi.

Sugeruję, abyś albo rozwiązał kontekst, i uważam, że Unity powinien mieć sposób na uniknięcie tworzenia 3 jego instancji, lub powinieneś rozważyć usługę fabryczną, która ma sposób na zbudowanie obiektu.

Na przykład, co jeśli później zdecydujesz się zbudować repozytorium, które w ogóle nie opiera się na tradycyjnej bazie danych, ale zamiast tego używa pliku XML do wygenerowania danych zastępczych do testu? Jak poszedłbyś na temat dostarczania treści XML do tego konstruktora?

IoC opiera się na kodzie odsprzęgającym, wiążąc typ i semantykę argumentów z konkretnymi typami, tak naprawdę nie zrobiłeś poprawnie odsprzęgania, nadal istnieje zależność.

„Ten kod może komunikować się z dowolnym typem repozytorium, o ile implementuje ten interfejs… Och, i używa kontekstu danych”.

Teraz wiem, że inne kontenery IoC mają na to wsparcie i miałem je również w mojej pierwszej wersji, ale moim zdaniem nie należy to do etapu rozwiązania.

</ 2 centy>

Dzięki chłopaki ... mój jest podobny do posta „Exist”. Patrz poniżej:

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

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

Możesz użyć InjectionConstructor/InjectionProperty/InjectionMethod w zależności od architektury wtrysku w ResolvedParameter <T> („nazwa”), aby uzyskać instancję wstępnie zarejestrowanego obiektu w kontenerze.

W twoim przypadku ten obiekt musi być zarejestrowany z nazwą, a dla tego samego ubezpieczenia potrzebujesz ContainerControlledLifeTimeManager () jak 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

Bardzo krótka odpowiedź brzmi: nie. Obecnie Unity nie ma możliwości przekazania parametrów do konstruktora, które nie są stałe ani wstrzyknięte, co udało mi się znaleźć. IMHO to jedyna największa rzecz, której brakuje, ale myślę, że jest to raczej projekt niż zaniedbanie.

Jak zauważa Jeff Fritz, teoretycznie można stworzyć niestandardowego menedżera dożywotniego, który wie, która instancja kontekstu ma być wprowadzana do różnych typów, ale jest to poziom twardego kodowania, który wydaje się eliminować cel używania Unity lub DI w pierwszej kolejności.

Możesz cofnąć się o krok od pełnej wersji DI i uczynić implementacje repozytorium odpowiedzialnymi za tworzenie własnych kontekstów danych. Kontekst instancja nadal może być rozwiązany z kontenera, ale logika przy podejmowaniu decyzji, który z nich będzie musiał przejść do implementacji repozytorium. Z pewnością nie jest tak czysty, ale pozbyłby się problemu.

3
Neil Hewitt

Inną alternatywą, której możesz użyć (nie wiem, czy to dobra praktyka, czy nie) jest utworzenie dwóch kontenerów i zarejestrowanie instancji dla każdego:

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

mam nadzieję, że to też pomaga

1
Samuel Carrijo

NotDan, myślę, że mogłeś odpowiedzieć na własne pytanie w komentarzach do lassevk.

Najpierw użyłbym LifetimeManager do zarządzania cyklem życia i liczbą wystąpień IDataContext tworzonych przez Unity.
http://msdn.Microsoft.com/en-us/library/cc440953.aspx

Wygląda na to, że obiekt ContainerControlledLifetimeManager zapewni ci zarządzanie instancjami, którego potrzebujesz. Mając ten LifetimeManager, Unity powinien dodać tę samą instancję IDataContext do wszystkich obiektów wymagających zależności IDataContext.

0
Jeff Fritz