2010-04-12 6 views
4

J'ai déjà posé cette question sur le forum MEF Codeplex, mais je n'ai pas encore reçu de réponse, alors j'ai pensé que j'essaierais StackOverflow. Voici le message original si quelqu'un est intéressé (ce qui est juste une copie de celui-ci):MEF + Plug-In ne pas mettre à jour

MEF Codeplex

« Permettez-moi de dire d'abord que je suis complètement nouveau pour MEF (vient de découvrir aujourd'hui) et je suis très heureux avec Cependant, j'ai rencontré un problème très frustrant: je crée une application qui aura une architecture de plugin et les plugins ne seront stockés que dans un seul fichier DLL (ou codés dans l'application principale) Le fichier DLL doit pouvoir être recompilé pendant l'exécution et l'application doit le reconnaître et recharger les plugins (je sais que c'est difficile, mais c'est une exigence) .Pour accomplir cela, j'ai pris l'approche http://blog.maartenballiauw.be/category/MEF.aspx là (cherchez WebServerDirectoryCatalog). L'idée est de "surveiller les plugins" dossier, copiez les assemblys nouveaux/modifiés dans le dossier/bin de l'application Web et demandez à MEF de charger ses exportations à partir de là. "Ceci est mon code, ce qui n'est probablement pas la bonne façon de le faire. le net:

 main()... 
    string myExecName = Assembly.GetExecutingAssembly().Location; 
     string myPath = System.IO.Path.GetDirectoryName(myExecName); 
     catalog = new AggregateCatalog(); 
     pluginCatalog = new MyDirectoryCatalog(myPath + @"/Plugins"); 
     catalog.Catalogs.Add(pluginCatalog); 


     exportContainer = new CompositionContainer(catalog); 

     CompositionBatch compBatch = new CompositionBatch(); 
     compBatch.AddPart(this); 
     compBatch.AddPart(catalog); 
     exportContainer.Compose(compBatch); 

et

private FileSystemWatcher fileSystemWatcher; 
    public DirectoryCatalog directoryCatalog; 
    private string path; 
    private string extension; 

    public MyDirectoryCatalog(string path) 
    { 
     Initialize(path, "*.dll", "*.dll"); 
    } 

    private void Initialize(string path, string extension, string modulePattern) 
    { 
     this.path = path; 
     this.extension = extension; 
     fileSystemWatcher = new FileSystemWatcher(path, modulePattern); 
     fileSystemWatcher.Changed += new FileSystemEventHandler(fileSystemWatcher_Changed); 
     fileSystemWatcher.Created += new FileSystemEventHandler(fileSystemWatcher_Created); 
     fileSystemWatcher.Deleted += new FileSystemEventHandler(fileSystemWatcher_Deleted); 
     fileSystemWatcher.Renamed += new RenamedEventHandler(fileSystemWatcher_Renamed); 
     fileSystemWatcher.IncludeSubdirectories = false; 
     fileSystemWatcher.EnableRaisingEvents = true; 
     Refresh(); 
    } 
    void fileSystemWatcher_Renamed(object sender, RenamedEventArgs e) 
    { 
     RemoveFromBin(e.OldName); 
     Refresh(); 
    } 
    void fileSystemWatcher_Deleted(object sender, FileSystemEventArgs e) 
    { 
     RemoveFromBin(e.Name); 
     Refresh(); 
    } 
    void fileSystemWatcher_Created(object sender, FileSystemEventArgs e) 
    { 
     Refresh(); 
    } 
    void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e) 
    { 
     Refresh(); 
    } 
    private void Refresh() 
    { 
     // Determine /bin path 
     string binPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins"); 
     string newPath = ""; 
     // Copy files to /bin 
     foreach (string file in Directory.GetFiles(path, extension, SearchOption.TopDirectoryOnly)) 
     { 
      try 
      { 
       DirectoryInfo dInfo = new DirectoryInfo(binPath); 
       DirectoryInfo[] dirs = dInfo.GetDirectories(); 
       int count = dirs.Count() + 1; 
       newPath = binPath + "/" + count; 
       DirectoryInfo dInfo2 = new DirectoryInfo(newPath); 
       if (!dInfo2.Exists) 
        dInfo2.Create(); 

       File.Copy(file, System.IO.Path.Combine(newPath, System.IO.Path.GetFileName(file)), true); 
      } 
      catch 
      { 
       // Not that big deal... Blog readers will probably kill me for this bit of code :-) 
      } 
     } 
     // Create new directory catalog 
     directoryCatalog = new DirectoryCatalog(newPath, extension); 
     directoryCatalog.Refresh(); 
    } 
    public override IQueryable<ComposablePartDefinition> Parts 
    { 
     get { return directoryCatalog.Parts; } 
    } 
    private void RemoveFromBin(string name) 
    { 
     string binPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ""); 
     File.Delete(Path.Combine(binPath, name)); 
    } 

donc tout cela fonctionne réellement, et après la fin du code principal ma variable IEnumerable est en réalité rempli de tous les plugins dans la DLL (qui, si vous suivez le code est situé dans Plugins/1 afin que je puisse modifier la DLL dans le dossier plugins). Donc maintenant, à ce stade, je devrais être capable de recompiler la DLL plugins, le déposer dans le dossier Plugins, mon FileWatcher détecter qu'il a changé, puis le copier dans le dossier "2" et directoryCatalog doit pointer vers le nouveau dossier . Tout cela fonctionne réellement! Le problème est, même s'il semble que tout est indiqué au bon endroit, ma variable IEnumerable n'est jamais mise à jour avec les nouveaux plugins. Si proche, mais pourtant si loin! Aucune suggestion? Je connais les inconvénients de le faire de cette façon, qu'aucune DLL n'est réellement déchargée et causant une fuite de mémoire, mais c'est une application Windows et sera probablement démarrée au moins une fois par jour, et les plugins sont peu susceptibles de changer souvent, mais c'est toujours une exigence du client de le faire sans recharger l'application. Merci!

Merci pour toute aide que vous pouvez tous donner, ça me rend fou de ne pas être en mesure de comprendre cela. »

Répondre

3

Il n'y a pas de déclencheur pour recompositions, parce que votre mise en œuvre de catalogue ne fournit pas les notifications. Mettre en œuvre INotifyComposablePartCatalogChanged à résoudre ce problème.

+0

Merci pour votre réponse, mais je ne vois pas comment cela m'aide.Après avoir joué encore un peu avec MEF, il me semble que je pourrais simplement changer mon implémentation de catalogue pour en faire une classe de stockage et me débarrasser de ComposablePartCatalog, puisque j'ai déjà un directoryCatalog dedans. DirectoryCatalog implémente INotifyComposablePartCatalogChanged, ce qui me semble signifier qu'il devrait mettre à jour les choses correctement si j'ai changé mon code dans main à catalog.Catalogs.Add (pluginCatalog.directoryCatalog) ;. – user64718

+0

@mybrokengnome: le conteneur MEF ne sera pas remarqué par magie si vous changez 'pluginCatalog.directoryCatalog' en un nouveau. Il sera toujours à l'écoute pour modifier les notifications de l'ancien. Il me semble que la notification de changement est très pertinente à votre question; Comment pourrait-il en être autrement? –

+0

Je ne le change pas après le cas, il pointe toujours vers pluginCatalog.directoryCatalog (un catalogue d'annuaire réel, pas un catalogue que j'ai créé). Puisque DC implémente INotifyComposablePartCatalogChanged je suis confus quant à pourquoi le DC ne découvre pas les nouveaux fichiers, même après que je crée un nouveau DC avec un nouveau chemin. Je reçois cette notification de changement est pertinente, mais A) Avec ma mise en œuvre actuelle (que je viens de décrire) alors la notification de changement est mis en œuvre via le DC MEF et B) Y at-il des exemples de ce qu'il faut faire pour implémenter travaillerait comme ça? – user64718

0

Je crois MEF ne peut charger une version du même ensemble (je tentais sur Silverlight cependant)

1

J'avais un issue- similaire après avoir copié Plugins découverts dans le répertoire de l'application, un wouldn DirectoryCatalog ne les voyez pas, même après avoir appelé .refresh() le e DirectoryCatalog. J'ai trouvé que le fait de passer le code a résolu le problème - ma meilleure estimation est que le système de fichiers a besoin d'un moment après que FileSystemWatcher ait déclenché sa notification avant que MEF puisse scanner le nouvel assemblage (peut-être pour terminer une opération de copie obscure) voir les pièces à l'intérieur. System.Threading.Thread.Sleep (1000), boiteux tel qu'il est, a résolu le problème.

Questions connexes