Nie dawno (patrz wpis: „Rozszerzanie aplikacji .NET (czyli plugin'y, add-in'y, MAF, MEF, itp. ...)”) wspomniałem na tym blogu o Managed Aadd-in Framework (zwanego
również System.AddIn lub MAF), przyjrzyjmy się bliżej temu rozwiązaniu.
Naszą przygodę z MAF zacznijmy może od powrotu to pokazanego wcześniej rysunku, który zaczerpnięty został z MSDN:
Muszę przyznać, że musiałem się chwilę zastanowić, gdy go
pierwszy raz zobaczyłem. Przedstawia on tzw. pipeline, czyli
ścieżkę prowadzącą przez poszczególne segmenty pomiędzy
aplikacją gospodarza (host'a) a wtyczką (add-in'em).
Wspomniana ścieżka jest właśnie wykorzystywana do komunikacji
pomiędzy aplikacją a jej wtyczką. Dlaczego zostało jednak to tak
skomplikowane?
Aby odpowiedzieć sobie na postawione pytanie zacznijmy może od
najprostszego przypadku (nie związanego z MAF!). Aplikacja (nazwijmy
ją Host) zawiera pewne komponenty (nie wtyczki, a raczej obiekty
klas współtworzących aplikację). W takim przypadku wspomniane
komponenty związane są bezpośrednio z aplikacją. Nie jest to
dobre rozwiązanie i każdy mający pewną wprawę w tworzeniu
oprogramowania wolałby taką zależność usunąć. Jak to zrobić?
Najprościej można to rozwiązać dodając pomiędzy wspomnianego
Hosta a Komponent dodatkowe elementy, które można nazwać
kontraktem. Taki kontrakt najczęściej ma postać klas
abstrakcyjnych lub interfejsów. Rozwiązanie to można przedstawić
na rysunku:
Jest to również najbardziej klasyczne podejście do rozwiązania
problemu z wtyczkami. Przykład takiego rozwiązania przedstawiłem
już kiedyś we wpisie: „Jak
zaimplementować mechanizm wtyczek (plugin'ów) w .NET (C#)”. W
MAF dodano jedna dodatkowy stopień komplikacji....
Wspomniane podejście (Host -> Kontrakt <- Komponent) ma pewną
znaczącą wadę, obydwa końce układanki są silnie zależne od
kontraktu i przez to wrażliwe na każdą jego zmianę. Jak ten
problem rozwiązać? Można wcisnąć pomiędzy wszystkie elementy,
jeszcze inne dodatkowe:
Dzięki temu ani Host, ani wtyczka (Add-in) nie są już zależne od
kontraktu (Contract), a wyłącznie zależą od swoich
widoków/spojrzeń na ten kontrakt (Host views of add-ins, Add-in
views) Wspomniane widoki/spojrzenia, to nadal klasy abstrakcyjne lub
interfejsy. Zwróćmy też uwagę, że dodane zostały dodatkowe
elementy dokonujące adaptacji pomiędzy widokiem, a kontraktem
(Host-side adapters, Add-inns-side adapters).
Właśnie taki zabieg dokonano w MAF i powstał wspomniany pipeline:
Rysunek z MSDN-u nie okazuje się więc zupełnie dziwaczny, ale
pewnie ktoś mógłby zapytać: „Czy muszę to wszystko wiedzieć?”
lub „Czy w moim prostym rozwiązaniu nie mogę jakiś elementów
pominąć?”. Otóż okazuje się, że trzeba to wiedzieć i pominąć
nie można. Ostatecznie można pewne rzeczy połączyć, ale takie
połączenie może okazać się nie do końca sensowne. Jest to
związane z faktem, że MAF wymaga odpowiedniej struktury katalogów,
w której znajdą się poszczególne kawałki powyższej układanki:
Zauważmy tutaj, że część katalogów jest wymagana
(HostSideAdapters, Contracts, AddInSideAdapters, AddInViews, AddIns).
W części z nich podkatalogi nie są dozwolone (HostSideAdapters,
Contracts, AddInSideAdapters, AddInViews). Natomiast w katalogu
AddIns wymagane są katalogi dla każdej wtyczki. Tym co są
przerażeni wspomnianymi ograniczeniami zostawiono niewielką
dowolność. Mianowicie dodatkowe wtyczki można umieścić w innym
katalogu (wskazanym podczas wyszukiwania rozszerzeń przez aplikację:
FindAddIns). Dowolna jest również lokalizacja całego pipeline'u
(na rysunku Pipeline root), ważne by miała wewnątrz odpowiednią
strukturę. Tym którzy nie będą chcieli się podporządkować
spotkają kary w postaci wyjątków, ostrzeżeń lub braku działania
wtyczki, np.:
- The assembly "C:\(…)\AddIns\DoSthV1SampleString\MAFSAmple1.Plugin.View.dll" should not be in location "C:\(…) :\(…)\AddIns\DoSthV1SampleString\". Remove it to avoid loader context problems.
- AddInSegmentDirectoryNotFoundException: The required folder "(...)\AddInSideAdapters" does not exist.
- Itp...
Na koniec do tak stworzonej struktury katalogów wystarczy powrzucać
odpowiednie assembly, które będą klasy lub interfejsy opatrzone
odpowiednimi atrybutami i połączone odpowiednimi zależnościami
zgodnie z rysunkiem:
Brak komentarzy:
Prześlij komentarz