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ń