Dziś będzie
prosty artykulik o katalogach, plikach, assembly, typach,
interfejsach itp... Czyli pokazane zostanie jak wykorzystać te
wspomniane elementy, by zaimplementować prosty mechanizm wtyczek
(plugin'ów) dla aplikacji.
Założenia:
- Chcemy mieć aplikację, która wykorzystuje mechanizm wtyczek;
- Wtyczka ma dostarczać pewien tekst (może robić co tylko zechcemy, ale przykład z założenia ma być prosty);
- Wtyczka będzie plikiem DLL, który znajdować się będzie w tym samym katalogu co aplikacja korzystająca z wtyczek.
- Każdy plik z wtyczką będzie się zaczynał od „Plugin”
Zastanówmy się
teraz jak to zaimplementować? Otóż najpierw potrzebny jest
interfejs, który będą wspierały nasze wtyczki, w naszym prostym
przykładzie może to być:
public interface IDoSth { string DoSth(); }
Każda wtyczka będzie musiała
posiadać publiczną klasę wspierającą ten interfejs, np.:
namespace PluginLibrary1 { public class Class1 : IDoSth { #region IDoSth Members public string DoSth() { return "Hello from Plugin Class"; } #endregion } }
Teraz czas na implementację głównego
programu, który przejrzy lokalny katalog, załaduje wszystkie
assembly pasujące do wzorca: „Plugin*.dll”. Następnie przejrzy
publiczne typy (klasy) i wybierze te, które wspierają interfejs
IdoSth. Powoła instancje tych typów i pobierze odpowiednie teksty z
wtyczek i wyświetli je na ekranie. Czyli uzyskamy kod podobny do:
class Program { static void Main() { //selecting current directory DirectoryInfo di = new DirectoryInfo("."); //checking all DLL files in the current directory that start from "Plugin" foreach(FileInfo fi in di.GetFiles("Plugin*.dll")) { //loading of the Plugin directory Assembly pluginAssembly=Assembly.LoadFrom(fi.FullName); //checking all public types from loaded assembly foreach( Type pluginType in pluginAssembly.GetExportedTypes()) { //now we are checking whether particular type implements //IDoSth interface if (pluginType.GetInterface(typeof(IDoSth).Name)!=null) { //creating the instance of selected type IDoSth TypeLoadedFromPlugin = (IDoSth)Activator.CreateInstance( pluginType ); //do sht with the plugin Console.WriteLine(TypeLoadedFromPlugin.DoSth()); } } } Console.ReadLine(); } }
Proste, prawda? To oczywiście dopiero
czubek góry lodowej, ale mam nadzieję, że główną ideę udało
mi się przekazać, przemycając dodatkowo trochę odnośnie
ładowania i przeglądania assembly.
A ja bym poprosił o to co jest poniżej tego czubka ;-)
OdpowiedzUsuńDla standardowych rozwiązań bardzo dobre rozwiązanie, dla już większych możliwości polecam MEF.
OdpowiedzUsuńo ;->
OdpowiedzUsuńskończę aktualny projekt to sobie to obadam, bo i tak planowałem napisać wtyczkowalną aplikacje, a póki co miała się opierać na dosyć dziwacznym rozwiązaniu ;-)
Witam,
OdpowiedzUsuńNo może z tym czubkiem góry lodowej, to przesadziłem... mechanizm który pokazałem działa i po prostu trzeba go uzupełnić o takie elementy jak:
- obsługę błędów,
- bezpieczeństwo i ograniczone zaufanie do czyjegoś kodu,
- identyfikację wtyczek,
- manager wtyczek,
- wyładowanie (unload) nie potrzebnych wtyczek,
- inne ...
Oczywiście jest jeszcze MEF, czyli Managed Extensibility Framework, ale przyznam, że jeszcze nim się nie zajmowałem.
W każdym razie dzięki za komentarze i być może coś się jeszcze w tym temacie na blogu pojawi.
Świetny artykuł na temat bardzo przydatnego mechanizmu :)
OdpowiedzUsuńCieszę się, ze Ci się podobał, jeżeli masz ochotę poczytać na ten temat więcej, to rozwinięcie tego tematu znajduje się tutaj: http://maciej-progtech.blogspot.com/2012/03/wprowadzenie-do-managed-add-in.html .
Usuń