Dependency injection – Autofac

Dzisiaj przechodzimy do opisu kontenera Autofac, czyli moim zdaniem kontenera, kt贸ry jest najlepszy 馃檪 je艣li chodzi o platform臋 .NET. U偶ywajac kontenera autofac mo偶emy wykorzysta膰 praktycznie wszystkie zalety jakie daj膮 nam kontenery.


Wst臋p

Autofac daje nam wszystkie zalety, kt贸re wymieni艂em w poprzednim artykule. Mo偶emy zapomnie膰 na wst臋pie o naszym kontenerze, kt贸ry napisali艣my. Nie dorasta on autofac-owi do st贸p 馃檪 zobaczmy zatem co takiego ciekawego ma autofac. Zacznijmy od podstawowego rejestrowania i tworzenia instancji klas.


Spokojnie, niekt贸rzy m贸wi膮, 偶e Autofac jest trudny, ale tutaj udowodni臋, 偶e to nieprawda 馃檪


Podstawowe u偶ycie Autofaca

Tak wygl膮da podstawowe rejestrowanie klas w autofac.

A je艣li tych klas mieliby艣my z 20 to troch臋 s艂abo by艂oby przepisywa膰 ka偶d膮 z nich. I na to jest spos贸b 馃檪

Wystarczy, 偶e dodamy takie co艣 do funkcji Main() bez rejestrowania po kolei ka偶dej z klas.

Jeden warunek musi by膰 taki, 偶eby klasa, kt贸r膮 rejestrujemy by艂a w tym samym projekcie, czyli struktura klas w projekcie musi wygl膮da膰 tak:

Widzimy, 偶e w naszym projekcie jest klasa ContainerConfig. W tej klasie mamy konfiguracj臋 Autofaca, 偶eby艣my nie musieli robi膰 tego w funkcji Main po to 偶eby mie膰 wszystko 艂adnie uporz膮dkowane.

Wydzielmy nasze klasy odpowiadaj膮ce za g艂贸wn膮 logik臋 do osobnej biblioteki i nast臋pnie zobaczmy jak to skonfigurowa膰, 偶eby wszystkie zale偶no艣ci pobra膰 automatycznie z wydzielonej biblioteki. Zatem jedziemy 馃檪

Teraz nasz projekt w sumie dwa projekty licz膮c bibliotek臋 wygl膮daj膮 tak:

Teraz zobaczmy jak wygl膮da klasa ContainerConfig.

Jak wida膰 w tej klasie wczytujemy zale偶no艣ci z biblioteki nast臋pnie rejestrujemy wszystkie zale偶no艣ci z interfejsami i na ko艅cu klas臋 GameServer.

呕eby to zadzia艂a艂o musimy tylko w funkcji Main rzecz jasna wywo艂a膰 metod臋 Configure() 馃檪

I wszystko ju偶 hula 馃檪


Rejestracja interfejs贸w jako Func

Obieca艂em w poprzednim artykule, 偶e wyja艣ni臋 o co dok艂adniej chodzi z Func. Chodzi o to, 偶e mo偶emy zarejestrowa膰 zale偶no艣膰 jako Func i pobra膰 z wywo艂ania tej rejestracji jaki艣 obiekt, kt贸ry z danej chwili jest nam potrzebny. Zaraz poka偶e to na przyk艂adzie

Mamy w klasie ContainerConfig co艣 takiego:

Zarejestrowali艣my wszystkie zale偶no艣ci oraz oznaczyli艣my je metod膮 Named() mo偶na powiedzie膰, 偶e przydzielili艣my tym rejestracjom klucze dzi臋ki kt贸rym ni偶ej w rejestracji Func b臋dziemy tworzy膰 instancj臋 tych rejestracji w zale偶no艣ci od przekazanego klucza 馃檪

W rejestracji Func b臋dziemy tworzy膰 instancje klasy LoginValidator albo singletona albo now膮 klas臋 w zale偶no艣ci od klucza.

W funkcji Main() mamy to 馃檪

Przekazujemy do rejestracji Func odpowiedni klucz i sprawdzamy, kt贸ra instancja to singleton a kt贸ra to normalna klasa.

Wynik jest taki:


Lifetime Objects

A jak to wygl膮da z czasem 偶ycia obiekt贸w w Autofac?

S膮 trzy najwa偶niejsze metody do zarz膮dzania 偶yciem obiekt贸w. Oto one:

To chyba nie musz臋 t艂umaczy膰 co ta linijka powy偶ej robi 馃檪

Ta metoda zawsze tworzy nowy obiekt instancji.

My u偶yjemy metody InstancePerDependency(), kt贸ra tworzy now膮 instancj臋, ale w ka偶dym kolejnym scopie. Zaraz poka偶e na przyk艂adzie 馃檪 Wygl膮da to tak:

Taka dodatkowa informacja 馃檪 Nie musimy rejestrowa膰 wszystkich interfejs贸w mo偶emy np zarejestrowa膰 interfejsy odpowiedzialne za walidacje danych, czyli interfejsy w folderze LoginPanel.

I w metodzie Main() mamy co艣 takiego:

I w ten spos贸b b臋dziemy tworzy膰 now膮 instancj臋 interfejsu ICharacterSkillPoints w ka偶dym nowym scopie, ale ka偶de kolejne utworzenie tej klasy sko艅czy si臋 przypisaniem wcze艣niej utworzonego obiektu 馃檪 Wynik 馃檪


Circular dependencies

Warto wyt艂umaczy膰 kwestie wzajemnych zale偶no艣ci, czyli co je艣li klasa A b臋dzie zale偶na od klasy B a klasa B b臋dzie zale偶na od klasy A? I na to jest spos贸b 馃檪

Mamy dwie klasy przyk艂adowe w klasie WebServer.

Za艂贸偶my, 偶e z klasy FirstClass chcemy pobra膰 liczb臋, kt贸ra jest w klasie SecondClass a z klasy SecondClass liczb臋, kt贸ra jest w klasie FirstClass. Jak mo偶emy to zrobi膰? Nie jest to takie trudne 馃檪 Dodajmy do klasy ContainerConfig co艣 takiego:

Czyli musimy wywo艂a膰 metod臋 .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies), 偶eby pozwoli膰 na wzajemne zale偶no艣ci i musimy zarejestrowa膰 te zale偶no艣ci jako .InstancePerLifetimeScope() lub .SingleInstance() nie mo偶emy tego robi膰 przez obiekt 偶ycia InstancePerDependency().

Jeszcze musimy tylko doda膰 scope do funkcji Main(), 偶eby to zadzia艂a艂o 馃檪

Wynik:

Ale to nie wszystko uzupe艂nianie zale偶no艣ci przez konstruktory nie jest wspierane. Gdy dodamy do naszych klas konstruktory:

To dostaniemy taki wyj膮tek:

Chyba, 偶e wstawimy konstruktor tylko do jednej z tych dw贸ch klas to wtedy te偶 nam zadzia艂a dobrze o tym wiedzie膰, 偶eby p贸藕niej si臋 nie zdziwi膰 馃檪

Dodatkowo warto wspomnie膰, 偶e Autofac posiada metod臋 Dispose() s艂u偶膮c膮 do czyszczenia kontenera a kt贸rej nie mia艂 nasz kontener.

Zapami臋taj to 馃檪


Interceptors

Kolejn膮 bardzo fajn膮 rzecz膮 w Autofac s膮 interceptory, kt贸re pozwalaj膮 zaimplementowa膰 programowanie aspektowe. Jako, 偶e uwa偶am to podej艣cie za ciekawe rozwi膮zanie to wykorzystamy to w naszym projekcie 馃檪

Ale czym s膮 interceptory? Umo偶liwaj膮 one przechwytywanie wywo艂a艅 metod przez inne komponenty. My u偶yjemy tego do 艣ledzenia dzia艂ania naszej aplikacji dzi臋ki temu b臋dziemy wiedzie膰 kiedy, jakie metody s膮 wywo艂ywane i co zwracaj膮.

W tym celu zacznijmy od naszej metody ContainerConfig i pozmieniajmy tam pare rzeczy.

Najpierw musimy zarejestrowa膰 klasy i oznaczy膰 je jako interceptory. Nast臋pnie musimy zarjestrowa膰 klas臋 CallLogger w kt贸rej b臋dziemy wywo艂ywa膰 komunikaty informuj膮ce co si臋 dzieje. Zobaczmy jak ona wygl膮da 馃檪

W tej klasie wy艣wietlamy wszystie komunikaty.

Ale to nie wszystko jeszcze musimy oznaczy膰 klasy, kt贸re chcemy przechwytywa膰. A mo偶na to zrobi膰 w ten spos贸b:

Taka sama procedura z klasami PasswordValidator i LoginValidator.

Na ko艅cu tworzymy zwyk艂ego scopa w kliencie.

I cieszymy si臋 jak to wszystko 艂adnie dzia艂a wynik jest taki:

Jak wida膰 kontenery jak i Autofac nie s膮 takie straszne 馃檪


Podsumowanie

S艂it 馃檪 To s膮 takie wa偶niejsze rzeczy z Autofaca jest tego troch臋 馃檪 Po reszt臋 odsy艂am do dokumentacji, kt贸ra i tak zreszt膮 jest bardzo dobra 馃檪 https://autofac.org/

Zbli偶a si臋 moja prezentacja o CQRS, wi臋c nied艂ugo i na blogu b臋dzie o CQRS a jeszcze p贸藕niej b臋dzie to w po艂膮czeniu z dependency injection.

Link do githuba ze wszystkimi przyk艂adami:https://github.com/Slaw145/Autofac

Standardowo, przypominam o newsletterze, kt贸rym wysy艂am powiadomienia o nowych wpisach oraz dodatkowe informacje na temat, og贸艂em m贸wi膮c, 艣wiecie IT.

KONIECZNIE do艂膮cz do spo艂eczno艣ci DevmanCommunity na fb, cz臋艣ci spo艂eczno艣ci jest w jednym miejscu 

-strona na fb: Devman.pl-S艂awomir Kowalski

-grupa na fb: DevmanCommunity

Pytaj, komentuj pod spodem na ko艅cu wpisu, podziel si臋 nim, oce艅 go, r贸b co wolisz 馃檪

 
Je艣li ten wpis ci si臋 przyda艂 podziel si臋 nim ze swoimi znajomymi :)

1
Post a comment

avatar
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Krzysiek Recent comment authors
  Subscribe  
newest oldest evaluated
Notify about
Krzysiek
Guest
Krzysiek

艢wietny artyku艂 馃檪