Cette source est composée de deux projets. Ils sont PluginGuest et PluginHost.
PluginGuest est le projet contenant la définition de la classe abstraite de plugin (PluginGuest.GenericPlugin) et de la fabrique (PluginGuest.PluginFactory). Cette fabrique est nécessaire pour récupérer les types des plugins déclarés dans n'importe quelle assembly. On peut alors les instancier avec la méthode CreateInstance(). La classe abstraite GenericPlugin défini 5 membres. Il y a trois propriétés. La première déjà implémentée, permet de récupérer le nom de l'assembly (GenericPlugin.Assembly) dans laquelle est déclaré le plugin. La seconde permet de récupérer le nom du plugin (GenericPlugin.Name) tel qu'il se le défini. La dernière permet de récupérer la catégorie de plugin (GenericPlugin.Category) dans laquelle se range le plugin. Les deux autres membres sont les fonctions appelées après le chargement (GenericPlugin.Load) du plugin et avant le déchargement (GenericPlugin.Unload) du plugin. La surcharge de la méthode ToString est faite pour afficher le nom de plugin.
PluginGuest contient aussi la définition des catégories de plugin (PluginGuest.PluginCategory) et des classes associées permettant d'avoir un dépôt de catégorie unique dans le domaine d'application principal. Une catégorie est ajoutée à l'aide de la méthode PluginCategory.AddCategory(). L'instance d'une catégorie est récupérée à l'aide de PluginCategorie.get_Category().
PluginHost est le projet contenant l'hébergeur de plugin en lui-même, l'interface des chargeurs de plugin, et deux chargeurs prédéfinis. L'interface des chargeurs de plugin (PluginHost.IPluginLoader) permet d'effectuer le chargement et le déchargement des assemblies des plugins. L'hébergeur de plugin (PluginHost.PluginManager<PluginType>) permet de gérer la synchronisation d'accès aux plugins et du chargement/déchargement de ceux-ci. La classe est statique uniquement. La généricité permet d'avoir de gérer plusieurs types de plugins clairement séparés, en plus de la séparation des catégories. Il y 4 méthodes pour les deux aspects d'utilisation : LockPlugins()/UnLockPlugins(), LoadPluginAssembly()/UnloadPlugins(). Le premier couple permet l'accès de façon sécurisée aux instances des plugins. Le second couple permet de charger et décharger les plugins. Le chargement et le déchargement sont mutuellement exclusifs. Ils ne peuvent non plus être exécuté lorsqu'il y a des plugins verrouillés. Le verrouillage de plugin ne peut plus être effecter dès qu'une demande de chargement ou déchargement est en attente de traitement.
L'utilisation des plugins se fait de la façon suivante : On démarre la boucle d'appels aux plugins avec la méthode PluginManager<PluginType>.LockPlugins() qui nous renvoie un tableau des instances de plugin (PluginType[]). LockPlugins() prend en paramètre la liste des catégories de plugins à verrouiller. PluginCategory.Categories peut être utilisé pour tout verrouiller. Il ne faut pas modifier le retour de LockPlugins. Une fois nos appels effectués, on utilise la méthode PluginManager<PluginType>.UnLockPlugins() en lui passant le tableau des plugins récupéré précédemment pour déverrouiller. Il ne faut plus utiliser le tableau de plugin. Il est impératif de suivre ce schéma afin de garantir le bon fonctionnement. L'oublie d'un déverrouillage bloque tout chargement et déchargement.
La méthode PluginManager<PluginType>.LoadPluginAssembly() prend le chemin absolu ou relatif au dossier de travail ou juste le nom du fichier s'il est dans les chemins de recherche et charge les plugins qui se trouvent dans l'assembly. Un booléen indiquant la réussite est renvoyé. Dans le cas d'un échec, l'exception peut être récupérée grâce à la propriété PluginManager<PluginType>.Errors (réinitialisable avec PluginManager<PluginType>.ResetErrors()). Le méthode PluginManager<PluginType>.UnloadPlugins() prend en paramètre le nom d'un des plugins de l'assembly à décharger et lance le déchargement de tous les plugins de l'assembly (Attention !). La valeur de retour possède les mêmes propriétés que la méthode explique précédemment.
Trois chargeurs de plugins sont disponibles : PluginHost.LocalLoader (par défaut), PluginHost.IPCLoader et PluginHost.TCPLoader. Ces trois chargeurs utilisent des domaines d'application séparés du domaine principal. Cette séparation permet le déchargement d'une assembly, sa mise à jour et son rechargement dans la nouvelle version. Si vous voulez écrire votre propre chargeur, consultez le code de ceux existants. Les deux derniers chargeurs utilisent des processus séparés pour communiquer. Le code des processus séparés sont dans les projets supplémentaires IPCPluginRunner et TCPPluginRunner. Les exécutables générés doivent obligatoirement se trouver dans le dossier de travail de l'application lorsque leur chargeur correspondant est utilisé.
Il y a quelques détails de fonctionnement à prendre en compte si vous utilisés mono. Il n'est pas possible sous mono de charger une nouvelle version d'une assembly même si elle était dans un domaine séparé du même processus. Le chargeur IPC ne fonctionne pas sous mono. Seul le chargeur TCP fonctionne avec mono. La détection étant celle du système d'exploitation, il ne faut pas utiliser mono sous windows pour utiliser cette bibliothèque.