2010-04-23 4 views
6

Chcę mieć aplikację, która działa jako host dla wielu innych małych aplikacji. Każda z tych aplikacji powinna działać jako rodzaj wtyczki do tej głównej aplikacji. Nazywam je wtyczkami nie w tym sensie, że dodają coś do głównej aplikacji, ale dlatego, że mogą pracować tylko z tą aplikacją hosta, ponieważ zależą od niektórych z jej usług.Pytanie o to, jak zaimplementować aplikację hosta C# z architekturą podobną do wtyczki.

Mój pomysł polegał na tym, aby każda z tych wtyczek działała w innej domenie aplikacji. Problem polega na tym, że moja aplikacja hosta powinna mieć zestaw usług, których moje wtyczki będą chciały używać iz tego co rozumiem, przepływ danych do iz różnych domen aplikacji nie jest niczym szczególnym.

Z jednej strony chciałbym, aby zachowywały się jak samodzielne aplikacje (chociaż, jak powiedziałem, muszą często używać usług aplikacji hosta), ale z drugiej strony chciałbym, aby którekolwiek z nich zawiesza się, moja główna aplikacja nie ucierpiałaby z tego powodu.

Jakie jest najlepsze (.NET) podejście do tego rodzaju sytuacji? Czy wszystkie działają na tym samym AppDomain, ale każdy z nich w innym wątku? Korzystasz z różnych domen aplikacji? Po jednym dla każdej "wtyczki"? Jak sprawić, by komunikowały się z aplikacją hosta? W inny sposób to zrobić?

Chociaż prędkość nie jest tu problemem, nie chciałbym, aby wywoływanie funkcji było znacznie wolniejsze niż w przypadku zwykłej aplikacji .NET.

Dzięki

EDIT: Może ja naprawdę trzeba używać różnych AppDomains. Z tego, co czytałem, ładowanie złożeń w różnych domenach aplikacji jest jedynym sposobem, aby później móc je usunąć z procesu.

Odpowiedz

5

Zaimplementowałem coś wzdłuż tych linii, używając Managed Addin Framework (MAF) w przestrzeni nazw System.Addin. Za pomocą MAF możesz spakować swoje dodatki jako oddzielne biblioteki DLL, które aplikacja hosta może wykryć i uruchomić w swojej domenie aplikacji, w oddzielnej domenie dla wszystkich dodatków lub każdego dodatku we własnej domenie. Z kopiowaniem w tle i oddzielnymi domenami można nawet aktualizować dodatek bez wyłączania hostapp.

Twoja aplikacja hosta i dodatki komunikują się poprzez umowy, które czerpiesz z interfejsów MAF. Możesz przesyłać obiekty pomiędzy hostem a dodatkami. Cotnracts zapewniają black-box interface pomiędzy dodatkami i hostem, pozwalając na zmianę implementacji adduktu bez wiedzy gospodarza.

Addiny mogą nawet komunikować się między sobą, jeśli host powie im o sobie nawzajem. W moim przypadku dodatek do logowania jest dzielony przez inne. To pozwala mi wpaść do różnych rejestratorów bez dotykania innych dodatków lub hosta.

Dla mojej aplikacji, addin używa prostych klas supervisora, które w klasach uruchamiania pracowników na własnych wątkach wykonują całe przetwarzanie. Pracownicy przechwytują własne wyjątki, które powracają do swojego przełożonego za pośrednictwem metod zwrotnych. Nadzorcy mogą ponownie uruchomić pracowników lub podjąć inne działania. Gospodarz kontroluje nadzorców poprzez umowę dowodzenia, która instruuje ich, aby zaczęli i zatrzymywali pracowników oraz zwracali dane.

Moja aplikacja hosta to usługa systemu Windows.W wątkach roboczych odrzucono wyjątki z wszystkich typowych przyczyn (w tym błędów!), Ale aplikacja hosta nigdy nie uległa awarii w żadnej z naszych instalacji. Ponieważ usługi debugowania są niewygodne, dodatki umożliwiają mi tworzenie aplikacji testowych wykorzystujących te same umowy, z dodatkową gwarancją, że testuję to, co wdrażam.

Addiny mogą również ujawniać elementy interfejsu użytkownika. Jest to bardzo pomocne, ponieważ muszę wdrożyć aplikację kontrolera w usłudze hosta, ponieważ usługi nie mają interfejsów użytkownika. Każda wtyczka zawiera własny interfejs kontrolera. Aplikacja kontrolera jest bardzo prosta - ładuje dodatki i wyświetla ich elementy interfejsu użytkownika. To pozwala mi wysyłać zaktualizowany dodatek z zaktualizowanym interfejsem i nie musi wysyłać nowego kontrolera.

Mimo że kontroler i usługa hosta używają tych samych dodatków, nie nakładają się one na siebie; w rzeczywistości nie wiedzą nawet, że inna aplikacja używa tych samych dodatków. Kontroler i host rozmawiają ze sobą za pośrednictwem wspólnej bazy danych, ale można również użyć innego mechanizmu aplikacji, takiego jak MSMQ. W następnej wersji host będzie usługą WCF z dodatkami na zapleczu i usługami sieciowymi do kontroli.

To jest trochę rozwlekły, ale chciałem dać ci wyobrażenie o tym, jak wszechstronny MAF jest. To nie jest tak skomplikowane, jak mogłoby się wydawać na pierwszy rzut oka, i można z niego tworzyć solidne aplikacje.

1

To jest pytanie interweniujące.

Moim pierwszym pomysłem było po prostu zaimplementować interfejsy z aplikacji hosta w aplikacjach wtyczek, aby umożliwić im komunikację za pośrednictwem Reflection, ale to tylko umożliwiłoby komunikację i nie przyniosłoby prawdziwej architektury podobnej do piaskownicy.

Moją drugą myślą było zaprojektowanie platformy zorientowanej na usługi. Aplikacja hosta byłaby rodzajem "nadawcy wtyczki", który publikowałby twoje wtyczki w ServiceHost w innym wątku. Ponieważ musi to być bardzo responsywna i "nie konfigurować mózgu", aplikacja hosta mogłaby komunikować się z wtyczką za pośrednictwem kanału nazwanych potoków (NetNamedPipesBinding for WCF), co oznacza, że ​​komunikuje się tylko z rurami localhost i nie potrzebuje żadnej konfiguracji sieci ani wiedzy w ogóle . Myślę, że to może być dobre rozwiązanie twojego problemu.

Pozdrawiam.

2

To zależy od tego, ile zaufania chcesz zezwolić na rozszerzenia. Pracuję nad podobną aplikacją i zdecydowałem się głównie zaufać kodowi rozszerzenia, ponieważ znacznie upraszcza to. Wstawiam kod ze wspólnego wątku (w moim przypadku rozszerzenia tak naprawdę nie "działają" w żadnej ciągłej pętli, ale raczej wykonują określone zadania, które chce wykonywać główna aplikacja) i przechwytują wyjątki w tym wątku, tak jak dostarczać pomocnych ostrzeżeń, że załadowane rozszerzenia źle się zachowują.

Obecnie nic nie stoi na przeszkodzie, aby rozszerzenia te nie uruchamiały własnych wątków, które mogłyby rzucić i zawiesić całą aplikację, ale w której musiałem dokonać kompromisu między bezpieczeństwem a złożonością. Moja aplikacja nie jest krytyczna dla misji (nie jak serwer WWW lub serwer bazy danych), więc uważam, że jest to dopuszczalne ryzyko, że błędne rozszerzenie może spowodować spadek mojej aplikacji.Zapewniam zabezpieczenia, aby bardziej grzecznie omówić najczęstsze przypadki niepowodzenia i pozostawić je deweloperom wtyczek (którzy w większości będą teraz osobami wewnętrznymi), aby wyczyścić swoje błędy.


W odniesieniu do rozładunku, tak, można jedynie rozładować kod i metadane dla zespołu, jeśli umieścić go w AppDomain. To powiedziawszy, jeśli nie chcesz, aby ładowanie i rozładowywanie było często wykonywane przez cały okres użytkowania programu, obciążenie związane z przechowywaniem kodu w pamięci niekoniecznie stanowi problem. Wszystkie rzeczywiste instancje lub zasoby korzystające z typów ze złożenia będą nadal czyszczone przez GC, gdy przestaniesz go używać, więc fakt, że wciąż jest w pamięci, nie oznacza przecieku pamięci.

Jeśli głównym przypadkiem użycia jest seria wtyczek, które można zlokalizować podczas uruchamiania, a następnie udostępnić opcję tworzenia wystąpienia podczas działania aplikacji, sugeruję zbadanie rzeczywistego śladu pamięci związanego z ładowaniem ich wszystkich podczas uruchamiania. i utrzymywanie ich w stanie załadowania. Jeśli użyjesz AppDomains, będzie tam również dodatkowy narzut (na przykład pamięć dla obiektów proxy i załadowany/JITed kod do obsługi marshaling AppDomain). Pojawi się również obciążenie procesora związane z serializacją i towarzyszącą serializacją.

Krótko mówiąc, chciałbym używać tylko AppDomains jeśli jeden z następujących były prawdziwe:

  • Chcę dostać prawdziwą Izolacja dla celów bezpieczeństwa kodu (czyli trzeba uruchomić kod niezaufane w odosobnionym sposób)

  • Moja aplikacja jest krytyczna dla misji i absolutnie muszę się upewnić, że jeśli wtyczka się nie powiedzie, nie może ona obniżyć mojej podstawowej aplikacji.

  • Muszę wielokrotnie ładować i usuwać tę samą wtyczkę, aby wspierać dynamiczne zmiany w bibliotece DLL. Dzieje się tak głównie wtedy, gdy moja aplikacja nie może przestać działać, ale chcę, aby wtyczki hot-patch były ciągle aktywne.

Nie preferowałbym AppDomains wyłącznie w celu ograniczenia potencjalnego śladu pamięci, umożliwiając zwolnienie.

+0

Jest to aplikacja do hobby, nic specjalnego. W pełni ufam uruchomieniu kodu. Problem polega na tym, że potrzebuję, aby każda z moich wtyczek działała cały czas (tzn. Nie mogę po prostu sprawić, aby moja aplikacja hosta wywoływała moje wtyczki, muszą one być niezależne i uruchamiać dla siebie.) –

+1

W takim przypadku po prostu dałbym każdy ma własny wątek do uruchomienia i wywołaj dowolną metodę "Main", którą zdefiniowałeś. Możesz zdecydować się na zawinięcie wywołania do "Main" z wątku w try/catch, jeśli chcesz zapewnić przyjazne wsparcie w przypadku, gdy wtyczka zgłasza wyjątek. –

+0

Tak, ale patrz powyżej. W ten sposób nie mogłem później wyładować złożonych zestawów bez restartowania aplikacji. Muszę je mieć w różnych domenach aplikacji, aby można je było rozładować, kiedy tylko chcę. –