begin process at 2010 02 10 06:11:38
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Système

 > [.NET2] HÉBERGEUR DE PLUGINS AVEC CHARGEMENT ET DÉCHARGEMENT DE PLUGINS

[.NET2] HÉBERGEUR DE PLUGINS AVEC CHARGEMENT ET DÉCHARGEMENT DE PLUGINS


 Information sur la source

Note :
10 / 10 - par 1 personne
10,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Système Source .NET ( DotNet ) Classé sous :plugin, chargement, déchargement, hébergeur, module Niveau :Initié Date de création :23/07/2007 Date de mise à jour :20/04/2008 23:09:04 Vu / téléchargé :4 901 / 202

Auteur : BaFM

Ecrire un message privé
Site perso
Commentaire sur cette source (6)
Ajouter un commentaire et/ou une note

 Description

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.


 Conclusion

Attention ! Les deux projets dépendent maintenant de log4net disponible sur le site http://logging.apache.org/. Il est important de rajouter les références nécessaires.

Il est possible d'imaginer des plugins qui seront eux-mêmes extensibles. C'est possible, l'hébergeur n'étant pas partagé avec les chargeurs par défaut. Et même si ce n'était pas le cas, il suffirait que ce ne soit pas le même type de plugin spécifié lors de l'utilisation de l'hébergeur. Il faudra donc faire attention dans ce cas aux déchargements en cascade.

Comme indiqué dans l'autre partie, les catégories de plugins sont gérées. L'ensemble des catégories disponible est enregistré dans le domaine d'application principal.

Au niveau des références de projet à définir, c’est assez simple. L’application principale doit référencer les deux projets. Le projet PluginHost référence PluginGuest, ce qui est logique puisqu’il va utiliser ses types. Les différents plugins vont référencer uniquement le projet PluginGuest. Il est conseillé de faire un autre projet qui va définir les classes abstraites des plugins du projet, permettant une meilleure aisance dans la demande des plugins et leur utilisation. Ce projet sera également référencé par les différents plugins et l'application principale. Je conseil d'utiliser au maximum des objets dérivant de MarshalByRefObject pour les objets communiqués entre les plugins et l'application principale. Les collections ne répondant pas à ce critère, il vous faudra soit écrire un objet d’encapsulation pour la liste implémentant tout l’interface, soit écrire un objet qui va contenir une ou plusieurs données avec les accesseurs et méthodes appropriées. Dans les deux cas, il faut l'utilisation de MarshalByRefObject. Rien ne vous empêche d’utiliser d’autres méthodes de communication entre l'application principale et les plugins, autre que l’appel de méthode, si l’envie vous prend.

Dans les déclarations de vos objets qui circulent entre l'application principale et les plugins, il faut veiller à ce que les interfaces que connais l'application principale soient les premières dans la liste des interfaces de l’objet, dans le cas contraire, il y a un risque qu’un type spécifique à votre plugin soit chargé dans le domaine de l'application principale et que la possibilité de déchargement soit bloquée pour ce plugin.

Ajout : Me disant que beaucoup aimeraient pouvoir utiliser les plugins en interface graphique et se demandent si c'est possible, je répondrais tout simplement que oui. Le classe de base de tous les contrôles Windows Forms, System.Windows.Forms.Control, étends directement MarshalByRefObject. Il est donc possible de faire une classe de plugin qui hérite directement d'un contrôle Windows Form et d'implémenter au minimum mon interface en première interface, voir une extension de celle-ci. Il sera plus prudent de fournir une propriété 'Control' dans l'interface qui sera implémentée par le plugin qui se renvoie lui-même avec le bon type Windows Forms. Il faudra veiller bien sur à implémenter la méthode Unload de manière à ce qu'elle déconnecte le composant de son parent, et si le composant peut être dupliqué, que tous les dupplicatas soient déconnectés aussi de leurs parents. Sinon c'est « vive les exceptions à la pelle » lors du prochain événement qui les atteindra ^^.

Je n’ai pas fournis d’exemple pour le moment, ca viendra peut-être. Je me suis inspiré d’un article sur CodeProject pour écrire cette source. Le lien est dans les fichiers sources qui ont récupérés des bouts de code de cet article.

Et je crois que c’est tout.

Au niveau de ce que j’ai à faire, voici la liste :
- Encapsuler le tableau des plugins par un objet qui va le placer en lecture seule. (collection en lecture seule)
- Commenter encore plus le code ^^
- Autre suggestions ?

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Historique

23 juillet 2007 16:37:47 :
Rajout de l'indication [.NET2] dans le titre pour pas que les gens essaient de le compiler sous 1.1 ou 1.0...
25 juillet 2007 14:29:28 :
Ajout du commentaire sur les Windows Forms.
09 avril 2008 00:30:12 :
Nouvelle version améliorée. - L'hébergeur supporte maintenant la généricité. Plusieurs contracts de plugins peuvent être utilisés. Ils pouront avoir un hébergeur dédié. - Le verouillage des plugins est amélioré. - Les noms ont été mis en anglais. - Plusieurs chargeurs de plugins peuvent être utilisés. Vous pouvez écrire vos propres chargeurs.
09 avril 2008 00:38:10 :
Nouvelle version revue et corrigée. - Hébergeur statique et générique, pour une meilleur synchronisation et un support de type de plugins multiple. - Possibilité de choisir le type du chargeur de plugin et d'en créer de nouveaux - Verrouillage revue et corrigé. - Gestion de catégories
20 avril 2008 23:09:05 :
Nouvelle version contenant l'implémentation des chargeurs hors-processus par IPC et par TCP. Le dernier permet enfin l'utilisation avec mise à jour de code sous mono.

 Sources du même auteur

Source avec Zip Source .NET (Dotnet) GESTIONNAIRE DE SERVER ET CLIENT DDE (DYNAMIC DATA EXCHANGE)
Source avec Zip Source avec une capture Source .NET (Dotnet) EXEMPLE UTILISATION HTTPWEBREQUEST, AFFICHER RÉPONSE HTTP À ...
Source avec Zip Source avec une capture Source .NET (Dotnet) CRC32 COMPATIBLE WINZIP ET WINRAR PAR DÉFAUT (GÉNÉRALISATION...
Source avec Zip Source .NET (Dotnet) CONTRÔLE LISTVIEW ÉDITABLE.

 Sources de la même categorie

Source avec Zip Source avec une capture Source .NET (Dotnet) GESTION DES LANGUES, COUNTRIES, CHAÎNES DE CARACTÈRE SIMPLE par gourky
Source avec Zip Source avec une capture Source .NET (Dotnet) EXPLORER LA MFT D'UNE PARTITION NTFS par Willi
Source avec Zip Source avec une capture Source .NET (Dotnet) WRAPPER COMPLET SUR L'API DE BIOMÉTRIE DE WINDOWS 7 par Willi
Source avec Zip Source .NET (Dotnet) UTILISER L'ASSISTANT DE GRAVURE DE WINDOWS par Willi
Source avec Zip Source avec une capture Source .NET (Dotnet) EASYDESKXP par neo2k2

 Sources en rapport avec celle ci

Source .NET (Dotnet) WEBTESTPLUGIN - IGNORER DES URLS LORS D'UN TEST WEB VISUAL S... par jesusonline
Source avec Zip Source .NET (Dotnet) MOTEUR DE PLUGINS AVEC CHARGEMENT/DÉCHARGEMENT par maitredede
Source avec Zip Source .NET (Dotnet) HOTPLUG MANAGER : GESTIONNAIRE DE PLUGINS INTERCHANGEABLES E... par Zeroc00l
Source avec Zip Source .NET (Dotnet) [XNA 1.0 REFRESH] GESTION PAR GAMESTATE par ricklekebekoi
Source avec Zip Source avec une capture Source .NET (Dotnet) PLUGIN PROGRAMME EXTENSIBLE GRÂCE AUX MODULES par badrbadr

Commentaires et avis

Commentaire de Warny le 25/07/2007 09:06:15

Dans le même esprit, j'ai fait cette source :
http://www.csharpfr.com/codes/CREATION-DYNAMIQUE-OBJETS_41547.aspx

Commentaire de BaFM le 25/07/2007 14:07:55

Sympa de faire la pub pour ta source Warny...
Enfin, là on a deux besoins différents (je fesais du même style que ce que tu as fait avant, mais avec des interfaces), ta source serait plutôt utile dans le cadre d'une application client qui peux être fermée/relancée si on veux virer des plugins. La mienne serait plutôt pour une application serveur ou une application client qui est assez lourde à charger. Ce qui signifie que l'on peux mettre un peu plus de contraintes à nos objets.

Commentaire de Warny le 25/07/2007 15:15:37

Ma source permet de précharger dans l'application cliente des DLL et les classes qu'elle contiennent en fonction d'une interface ou d'une classe de base puis d'instancier les objets à la demande. Mais je peux aussi enlever des classes de l'instancieur sans problème (c'est une collection). Si j'ai bien compris ce que fait ta source, c'est qu'elle précharge les classes pour pouvoir les utiliser dans un programme externe, non ? Sinon, c'est mal expliqué.
Mon principe surtout d'utiliser une classe paramétrable qui permet d'utiliser n'importe quelle classe ou interface de référence. Le principe peut certainement être réappliqué à ton cas.

Commentaire de BaFM le 25/07/2007 15:31:51

Tu n'a pas compris. Essaie avec ta version de charger une autre version d'une assembly, normalement, ca plantera. Car il verras que tu as déjà chargé l'assembly ou parce qu'il te diras qu'il peut pas la charger. Avec la solution que je propose, tu peux avoir de chargé en même temps, plusieurs versions d'un même assembly. De plus ce n'est pas juste les objets ou les informations de type que je décharge, c'est toutes les informations de type. Si tu garde le pointeur vers un plugin, puis que tu décharge le plugin et donc toute l'assembly et le domaine d'application qui va avec, et que après tu essaie d'appeler un méthode sur l'objet, il te dirat tout simplement : "Impossible d'effectuer l'appel, le composant distant n'est plus disponible." Enfin un truc du style.
Après je part d'un interface et pas d'une classe d'une part parce que c'est moins contraignant à écrire et le concepteur gère le fait de te demander d'implémenter directement au niveau de l'éditeur, pas besoin de taper override, et d'autre part pour permettre d'hériter d'une classe dérivant de MarshalByRefObject et pas obligatoirement de MarshalByRefObject. Puisque ma source peu être utilisée tel qu'elle pour définir n'importe quel type de plugin personnalisé, puisque ca ne contient que les informations nécessaire à l'hébergeur, c'est à la personne qui va l'utiliser d'implémenter son interface de plugin en implémentant celui de l'hébergeur.
Il est vrai que je n'ai pas expliquer le principe sur lequel ca se basait et sur quel niveau exactement se fesait le déchargement, qui est je le reprécise au niveau de code et des meta donnees en eux-mêmes et pas seulement des données.
J'espère avoir réussi a te faire comprendre la légère différence de fonctionnalité.

Commentaire de medelidrissi le 09/10/2007 20:44:10 10/10

Félicitations, très bonne source.

Dommage que ce n'est pas commenté. Autrement, je pense que le plus important est dit dans la description :d.

Bonne Programmation.

Commentaire de BaFM le 14/04/2008 20:03:37

Bonjour,
Pour ceux qui suivent la source, une nouvelle version plus puissante, plus clair, et plus commentée a été publie il y a quelques jours. Suite à une étrangeté, la mise à jour est marquée deux fois, mais c'est rien, c'est là même. Tout le texte de la source a été mis à jour aussi, il faut donc relire.

MyGoddess

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Creation d'un plugin IE [ par LAlex ] Salut TLM !Je suis en train d'effectuer le portage d'une application Client/Serveur en n-Tiers pour le Web. L'application existante génère un document Erreur avec DateTime [ par heriquet ] Bonjour.J'ai un problème assez ennuyeux avec une date.J'ai une application en C# qui tourne avec une base Access.Quand j'ouvre un formulaire de donnée calculer le temps de chargement d'une page asp.net [ par Cameleon69 ] Je cherche comment claculer le temps de chargement d'une page asp.net en C#.J'ai bien trouvé un code en vb ou vb.net mais le problème c'est qu'il util Problème de console au chargement de la form [ par Jujufouq ] Bonjour à tous!Je ne sais pas si ce problème a déjà été posté, mais j'ai ce problème. Voici mon code :using System;using System.Windows.Forms;class fr Utilisation de process [ par Yandroide ] bjour,Je lance une application d'ocr et je lui passe des images en paramètres grace à process. J'utilise MonProcess.WaitForInputIdle() pour faire atte Help ! comment faire un update de la base en saisissant sur un datagrid [ par kikoff ] ben voila je resume mon probleme :j'ai un projet en winform avec un datagridje charge ce datagrid avec un dataset (ds) qui est construit de la maniere Problème d'unload de plugin [ par revlis ] Bonjour a tous, J'ai fait une petite application composée de modules (plugin)Chaque dll presente dans un sous-repertoire représente un "module". celui .ascx et Varuables Sessions [ par ousta ] Salut j'ai un module en .ascx qui peut etre présent sur differentes pages, dans ce module jinitialise une variable Session et voici ce quil me dit au Utilisation conjointe de vb.net et de C# [ par ClaudeMM ] Je désire écrire un programme composé d'un module écrit en C# pour la supervisation et l'interface utilisateur et un module écrit en VB.NEt pour un tr Assembly.GetInterfaces() [ par jusob ] Bonjour, J'ai un programme qui doit charger des DLLs. Ces DLLs impl&#233;mentent l'interface PluginInterface. Programme principal: foreach (Typ


Nos sponsors


Sondage...

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,874 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales