Castle Windsor - warunkowe wstrzykiwanie zależności

0

Mam sobie solucję, która zawiera między innymi dwa projekty.

  1. Backend - logika biznesowa, context DB (nazwijmy go DBContextBE) dziedziczący po DbContext z którego korzysta logika biznesowa.
  2. API - tutaj znajduje się drugi context DB (nazwijmy go DBContextAPI) dziedziczący po DbContext z którego korzystają niektóre metody w tym projekcie.

Natomiast po stronie backendu (projekt punkt 1) jest adapter EF zawierający metody zapisu, aktualizacji czy tworzenia obiektów modeli bazy danych.
Po stronie API część metod z kontrolera odwołuje się do lokalnej logiki i DBContextAPI, a część metod do logiki z backendu (punkt 1) gdzie potrzebny jest DBContextBE.
I tutaj mam problem. Jak zarejestrować po stronie API dany context DB w zależności od tego, która logika jest w danym momencie używana?
Np. odpalam metodę z kontrolera API, która korzysta z logiki na backendzie gdzie operujemy na DBContextBE i gdy jest używana metoda z klas backendowych to rejestruję DBContextBE gdyż w konstruktorze adaptera EF oczekiwany jest obiekt klasy DBContext.

public void Install(IWindsorContainer container, IConfigurationStore store)
        { 
            container.Register(Component.For<IDbContextAdapter>()
                .ImplementedBy<EfDbContextAdapter>()
                .LifestyleTransient());
           
            //Odpalam metodę wykorzystującą logikę z backendu to do EfDbContextAdapter potrzebuję wstrzyknąć DBContextBE
            container.Register(Component.For<DbContext>()
                .ImplementedBy<DBContextBE>()
                .LifestyleTransient());
            
             //Odpalam metodę wykorzystującą logikę z API to do EfDbContextAdapter potrzebuję wstrzyknąć DBContextAPI
            container.Register(Component.For<DbContext>()
                .ImplementedBy<DBContextAPI>()
                .LifestyleTransient());
}

Jak to uwarunkować? A w zasadzie jak poznać na etapie rejestracji, że w danym momencie jest uruchamiana dana metoda?

2

Zrób fabrykę, która będzie zwracała odpowiedni obiekt, w zależności od warunków
.Albo lepiej użyj różnych typów, a nie jednego.

0

Taka fabryka oparta na swich'u zazwyczaj łamie open/closed principle.

Ja bym wolał zarejestrować implementacje IDictionary, która by działała jak IIndex z Autofac'a.

Potem robisz sobie kompozyt, który wybiera kontekst na podstawie argumentu z dictionary.

2
Gworys napisał(a):

Potem robisz sobie kompozyt, który wybiera kontekst na podstawie argumentu z dictionary.

Czyli fabrykę.

0

Panowie nie wiem co tu się odpikoliło, ale generalnie jeszcze średnio łapię Wasze specjalistyczne określenia. Najlepiej jak byście mogli mi podrzucić jakiś przykład.
Co nieco już programuje i sporo rzeczy mi się udało zrobić, głównie bazując na przykładach ze stacka czy innych, ale nie są mi znane jeszcze wszystkie zagadnienia, które mógłbym z kimś przedyskutować face tu face. Dlatego też chyba potrzebuję aby ktoś mi wytłumaczył jak krowie na rowie.
Co to znaczy zrobić fabrykę zwracającą odpowiedni obiekt?
Ta fabryka będzie operowała rejestracją w windsorze?
I teraz nie bardzo wiem jak sprawdzić z poziomu windsora, który context jest używany.

2

Możesz sobie napisać klasę jak ta:

public class DbContextProvider
{
    private DbContext dbContextApi, dbContextBe;

    public DbContextProvider(DBContextAPI dbContextApi, DBContextBE dbContextBe)
    {
        this.dbContextApi = dbContextApi;
        this.dbContextBe = dbContextBe;
    }	
	
    public DbContext CreateContext()
    {
        if(warunek API)
            return this.dbContextApi;
        else if (warunek BE)
            return this.dbContextBe;
		
        throw new Exception();
    }
}

Potem ją skonfigurować w Windsorze i wstrzykiwać do klas potrzebujących DbContextu.

Ale czemu nie wstrzykiwać DBContextAPI i DBContextBE tam gdzie potrzebne, zamiast oba konfigurować jako DBContext?

0

Nie ma żadnego profitu z tego, że wstrzykujesz te konteksty do tego prvaidera, mniejsza z tym, że jest to słaba nazwa.

Poza tym łamiesz OCP każda próba rozszerzenia klasy "provaidera" będzie się łączyła dopisywaniem kolejnego ifa i dopisywania nowego parametru do konstruktora.

Opcja Gworysa jest o wiele lepsza. Mało tego też bym się wnerwił na jego miejscu.

I niby czym się różni ta fabryka na ifach od tej na switchu.?

0

to pokaż jak byś to zrobił zgodnie z koncepcją Gworysa. Wtedy każdy będzie mógł popatrzeć na dwie implementacje i sam zdecydować co jest lepsze i w jakiej sytuacji :)

Domyślam się, że chodzi w uproszczeniu mniejwięcej o coś takiego:

//contener IOC
builder.RegisterType<Context<DbAPI>>().Keyed("arg1");
builder.RegisterType<Context<DbBE>>().Keyed("arg2");

//Gdzieś w logice
Dictionary.Key("arg1").Context()

No i....

0

No to, że Ty na myśl fabryka myślisz switch albo service locator to już nie jest nasz problem, nie jest to też problem rozwiązywalny na forum programistycznym.

Moim zdaniem to, co ktoś sobie myśli na myśl Fabryka to nie istotne, bo to tylko wysokopoziomowy interfejs za fabryką może być cokolwiek. Jakaś fasada, service locator, whatever...

@somekind To mistrz wykorzystywania homonimy. Prowadzi debaty z poziomem co najmniej dzisiejszych liderów PO, lecz wiedzy technicznej dalej mu brakuje...

0
Mimik59 napisał(a):

Nie ma żadnego profitu z tego, że wstrzykujesz te konteksty do tego prvaidera, mniejsza z tym, że jest to słaba nazwa.

Pewnie, że nie ma. Dlatego napisałem, że tak można zrobić, ale żeby tego nie robić.

Poza tym łamiesz OCP każda próba rozszerzenia klasy "provaidera" będzie się łączyła dopisywaniem kolejnego ifa i dopisywania nowego parametru do konstruktora.

Owszem. Jeśli komuś nie podoba się łamanie OCP, to zawsze może sobie napisać mądrzej:

public class DbContextProvider
{
    private CleverDbContext[] contexts;

    public DbContextProvider(CleverDbContext[] contexts)
    {
        this.contexts= contexts;
    }   

    public CleverDbContext CreateContext()
    {
        foreach (var ctx in this.contexts)
             if (ctx.CanBeUsed(/*pewnie jakieś parametry*/)
                 return ctx;

        throw new Exception();
    }
}

Ale to dalsze bredzenie w overengineering, podczas gdy tak naprawdę rozwiązywany jest tu chyba problem X/Y, a prawidłowym i działającym rozwiązaniem jest niebindowanie tych kontekstów do klasy bazowej, bo skoro nie są używane zamiennie, to żadnego pożytku z takiej konfiguracji nie ma.

I niby czym się różni ta fabryka na ifach od tej na switchu.?

No generalnie tym, że w ifach można mieć wyrażenia logiczne, a w switchu nie. (Chyba jednak usunięcie Newbie było złym pomysłem, skoro takie pytania się pojawiają.)

Domyślam się, że chodzi w uproszczeniu mniejwięcej o coś takiego:

//contener IOC
builder.RegisterType<Context<DbAPI>>().Keyed("arg1");
builder.RegisterType<Context<DbBE>>().Keyed("arg2");

//Gdzieś w logice
Dictionary.Key("arg1").Context()

No tak, magiczne stringi są tak bardzo lepsze niż ify. :)

Opcja Gworysa jest o wiele lepsza. Mało tego też bym się wnerwił na jego miejscu.

Ja na jego miejscu też bym się wkurzył, że ktoś pisze z jego komputera i twierdzi, że nie jest nim.

PS, dużo jest Was tam, w środku?

0

No generalnie tym, że w ifach można mieć wyrażenia logiczne, a w switchu nie. (Chyba jednak usunięcie Newbie było złym pomysłem, skoro takie pytania się pojawiają.)

Gdybyś nie żył w średniowieczu wiedziałbyś, że to nieprawda.

case Apple apple when apple.Color == Color.Brown:

Poza tym, nie wiem co to ma wspólnego z tematem, pewnie odwrucenie uwagi.

f (ctx.CanBeUsed(/pewnie jakieś parametry/)

No a tutaj pewnie będzie magiczny int.? Ablo magiczny parametr.

No tak, magiczne stringi są tak bardzo lepsze niż ify. :)

Brak nawiązania do tematu, kolejne odwrócenie uwagi.
Może sobie nawet magicznego boolena tam wpisać. Co mnie to obchodzi.?

Ja na jego miejscu też bym się wkurzył, że ktoś pisze z jego komputera i twierdzi, że nie jest nim.

PS, dużo jest Was tam, w środku?

Jak to się dzieje, że ty ich wszędzie widzisz.?

Ps. sprawdź czy czasem jakiś Gworys ci się nie schował pod łóżkiem.

Ale to dalsze bredzenie w overengineering, podczas gdy tak naprawdę rozwiązywany jest tu chyba problem X/Y,

Twoje rozwiązanie wymaga stworzenia większej ilości obiektów, Więc tym bardziej jest overengineering'iem.

0
Mimik59 napisał(a):

case Apple apple when apple.Color == Color.Brown:

Poza tym, nie wiem co to ma wspólnego z tematem, pewnie odwrucenie uwagi.

No ja też nie wiem, co ten kod ma do rzeczy, na pewno nie rozwiązuje aktualnego problemu.

No a tutaj pewnie będzie magiczny int.? Ablo magiczny parametr.

Nie wiem, nie znam reguł wyboru odpowiedniego kontekstu. Te zna tylko autor wątku, jego pytaj.

Fafnasty raz powtarzam - najlepiej użyć rejestracji typów, fabryka jest możliwym, ale prawdopodobnie nie najlepszym rozwiązaniem tego problemu.

0
somekind napisał(a):
Mimik59 napisał(a):

case Apple apple when apple.Color == Color.Brown:

No ja też nie wiem, co ten kod ma do rzeczy, na pewno nie rozwiązuje aktualnego problemu.

Wypowiedź, do której nawiązuje też nie. No i co z tego.?

Fafnasty raz powtarzam - najlepiej użyć rejestracji typów, fabryka jest możliwym, ale prawdopodobnie nie najlepszym rozwiązaniem tego problemu.

Fafnasty raz powtarza, że taka fabryka, jaką proponowałeś, jest błędnym rozwiązaniem.

Uciekasz od tego faktu a sam sprowokowałeś kłótnie, która odnosi się do tematu owej fabryki na swichach czy tam ifach.

Czyli po prostu mataczysz, ponieważ nie jesteś wartościowym użytkownikiem tego forum a tym bardziej moderatorem z którym warto się liczyć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1