2013-04-22 8 views
10

MEF-Laufzeitplugin-Update Problem

Problem

Mein MEF-Code aktualisiert Assemblys während der Laufzeit nicht ordnungsgemäß aus einem Ordner, der einem DirectoryCatalog zugeordnet ist. Die Plugins werden zur Laufzeit erfolgreich geladen, aber wenn ich die DLL aktualisiere und Refresh im DirectoryCatalog anrufe, werden die Assemblys nicht aktualisiert.

Hintergrund

Ich baue eine DLL, die einen MEF-Container hat, und verwendet ein DirectoryCatalog, um einen lokalen Plugin-Ordner zu finden. Ich rufe diese DLL derzeit aus einem einfachen WinForm, das ist mit einem separaten Projekt, um ShadowCopy zu verwenden, so dass ich die DLLs in meinem Plugin-Ordner überschreiben kann. Anstatt einen FileWatcher zu verwenden, um diesen Ordner zu aktualisieren, mache ich eine öffentliche Methode verfügbar, die eine Aktualisierung im DirectoryCatalog aufruft, sodass ich die Assemblies nach Belieben aktualisieren kann, anstatt automatisch.

-Code

Basisklasse instanziiert die MEF Kataloge und Behälter, und speichert sie als Klassenvariablen für Referenz Zugriff später

public class FieldProcessor 
{ 
    private CompositionContainer _container; 
    private DirectoryCatalog dirCatalog; 

    public FieldProcessor() 
    { 
     var catalog = new AggregateCatalog(); 
     //Adds all the parts found in the same assembly as the TestPlugin class 
     catalog.Catalogs.Add(new AssemblyCatalog(typeof(TestPlugin).Assembly)); 
     dirCatalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory + "Plugin\\"); 
     catalog.Catalogs.Add(dirCatalog); 

     //Create the CompositionContainer with the parts in the catalog 
     _container = new CompositionContainer(catalog); 
    } 

    public void refreshCatalog() 
    { 
     dirCatalog.Refresh(); 
    } 

} ... 

hier ist das Plugin ich versuche, zu überschreiben. Mein Test der Aktualisierung ist, dass die zurückgegebenen Stiche in ein Textfeld ausgegeben werden. Ich ändere die Strings, die das Plugin zurückgibt, neu erstellen und in den Plugin-Ordner kopieren. Aber es wird nicht für die laufende App aktualisiert, bis ich die App schließe und neu starte.

[Export(typeof(IPlugin))] 
[ExportMetadata("PluginName", "TestPlugin2")] 
public class TestPlugin2 : IPlugin 
{ 
    public IEnumerable<IField> GetFields(ContextObject contextObject, params string[] parameters) 
    { 
     List<IField> retList = new List<IField>(); 
     //Do Work Return Wrok Results 
     retList.Add(new Field("plugin.TestPlugin2", "TestPluginReturnValue2")); 
     return retList; 
    } 
} 

bearbeiten

Import Statement

[ImportMany(AllowRecomposition=true)] 
    IEnumerable<Lazy<IPlugin, IPluginData>> plugins; 

Forschung

ich ziemlich umfangreiche Forschung und überall erscheint in Artikeln und Codebeispiele die Antwort zu sein, ein Directory in einen Behälter hinzuzufügen getan haben und sparen eine Referenz dieses Katalogs, dann Refresh auf dieser Referenz aufrufen, nachdem ein neues Plugin hinzugefügt wurde, und es wird die Assemblys aktualisieren ... was ich tue, aber es zeigt keine aktualisierte Ausgabe von der neuen Plugin-DLL.

Anfrage

Hat jemand dieses Problem gesehen oder weiß, was meine Probleme mit den Assemblys verursacht, die während der Laufzeit nicht aktualisiert werden? Jede zusätzliche Information oder Einsicht wäre willkommen.

Auflösung

Danke an Panos und Stumpy für ihre Links, die mich zur Lösung meines Problems geführt haben. Für zukünftige Wissensucher bestand mein Hauptproblem darin, dass die Refresh-Methode Assemblys nicht aktualisiert, wenn die neue Assembly genau denselben Assemblynamen wie die überschriebene Dll hat. Für meinen POC habe ich gerade den Umbau mit einem Datum getestet, das an den Assemblynamen angehängt wurde, und alles andere gleich, und es funktionierte wie ein Zauber. Ihre Links in den Kommentaren unten waren sehr nützlich und werden empfohlen, wenn Sie das gleiche Problem haben.

+1

DirectoryCatalog.Refresh wird aktualisierte Aufbauten nicht erkennen. Nur neue oder gelöschte. Werfen Sie einen Blick auf diese Antwort für eine Problemumgehung und Vorschläge: http://StackOverflow.com/a/14842417/850119 –

+0

Meine DLLs sind gesperrt, wenn sie geladen sind, so kann ich sie mit neuen DLLs überschreiben. Hattest du dieses Problem nicht? hast du etwas gemacht, das sie aktualisierbar gemacht hat? –

+0

Ja, ich hatte dieses Problem. Einer der Schritte, die ich im Vorbeigehen erwähnte, war "Schattenkopie". Mit Shadow Copy kann ein Programm lokale Kopien von DLL-Assemblys erstellen und sie einem lokalen Cache hinzufügen, anstatt die DLLs zu sperren. Dies muss aktiviert sein, damit Sie während der Laufzeit dlls "hot swap" austauschen können. Andernfalls müssen Sie das Programm stoppen, die dlls ändern und es dann neu starten. Ich denke, das ist das Beispiel, das ich angeschaut habe, aber wenn es für dich nicht funktioniert, google MEF und Shadow Copy, http://stackoverflow.com/questions/12593308/mef-and-shadowcopying-dlls-so-that-i -can-overwrite-them-at-runtime – Madullah

Antwort

3

Haben Sie den Parameter AllowRecomposition auf Ihr Importattribut gesetzt?

AllowRecomposition 
Gets or sets a value that indicates whether the property or field will be recomposed when exports with a matching contract have changed in the container. 

http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.importattribute(v=vs.95).aspx

edit:

Directory nicht Baugruppen aktualisieren, wird nur hinzugefügt oder entfernt: http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.hosting.directorycatalog.refresh.aspx

für eine Arbeit um: https://stackoverflow.com/a/14842417/2215320

+0

Ich tat, tut mir leid, ich habe den Import-Anweisung Code ursprünglich nicht veröffentlicht, ich habe die Frage aktualisiert, um meine Import-Anweisung widerzuspiegeln. – Madullah

+0

und Ihr Refresh-Code? Ich denke, das Problem ist drinnen. Sie haben angegeben, FileSystemWatcher nicht zu verwenden. Wie erkennen und laden Sie Ihre Assemblys neu? – Niels

+0

Ich zeige es durch die RefreshCatalog-Methode an, die oben zu sehen ist. Ich rufe diese Methode von einem Button-Click-Event auf einer WinForm aus. – Madullah