2010-04-12 57 views
4

我在MEF Codeplex論壇上已經提出這個問題,但我還沒有得到答覆,所以我想我會嘗試StackOverflow。這裏是原來的職位,如果任何人的興趣(這只是一個從它複印件):MEF +插件沒有更新

MEF Codeplex

「讓我先說,我完全新的MEF(今天才發現了它),我非常高興但是,我遇到了一個非常令人沮喪的問題,我創建了一個具有插件體系結構的應用程序,插件只會存儲在一個DLL文件中(或者編碼到主應用程序中)。DLL文件需要能夠在運行時重新編譯,應用程序應該識別這個並重新加載插件(我知道這很困難,但這是一項要求)。爲了實現這一點,我採取了包括http://blog.maartenballiauw.be/category/MEF.aspx那裏(尋找WebServerDirectoryCatalog)。基本上這個想法是「監控插件文件夾中,將新的/修改過的程序集複製到Web應用程序的/ bin文件夾中,並指示MEF從那裏加載它的導出。「這是我的代碼,可能不是正確的方法,但這是我在某些示例中發現的淨:

 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); 

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)); 
    } 

所以這一切的實際工作,並在主我的IEnumerable變量的代碼結束後竟充滿DLL中所有的插件(其中,如果你請按照代碼位於插件/ 1,以便我可以修改插件文件夾中的DLL)。 因此,現在我應該能夠重新編譯插件DLL,將它放入Plugins文件夾,我的FileWatcher檢測到它已更改,然後將其複製到文件夾「2」中,並且directoryCatalog應該指向新文件夾。所有這些 實際上工作!問題是,儘管看起來每件事都指向了正確的位置,但我的IEnumerable變量永遠不會被新的插件更新。如此接近,但迄今爲止!有什麼建議麼? 我知道這樣做的缺點,沒有DLL實際上是卸載並導致內存泄漏,但它是一個Windows應用程序,並可能會啓動至少每天一次,並且插件不可能更改 通常情況下,但它仍然是客戶的要求,它在不重新加載應用程序的情況下執行此操作。謝謝!

感謝您的幫助,您都可以提供,它的駕駛我瘋狂不能夠想出解決辦法「。

回答

3

沒有觸發重新組合,因爲你的目錄下,執行不提供通知。實施INotifyComposablePartCatalogChanged到解決這個問題。

+0

感謝您的回覆,但我不明白這對我有何幫助。在更多地使用MEF之後,似乎我可以將我的目錄實現更改爲基本的存儲類,並且擺脫ComposablePartCatalog,因爲我已經有了一個directoryCatalog。 DirectoryCatalog確實實現了INotifyComposablePartCatalogChanged,這對我來說意味着它應該正確地更新東西,如果我將主代碼更改爲catalog.Catalogs.Add(pluginCatalog.directoryCatalog);. – user64718 2010-04-13 03:13:24

+0

@mybrokengnome:如果將'pluginCatalog.directoryCatalog'更改爲新的,MEF容器不會奇蹟般地注意到。它仍然會聽取更改舊通知的通知。在我看來,變更通知與您的問題非常相關;它怎麼會不是? – 2010-04-13 08:54:49

+0

我沒有改變它的情況下,它現在總是指向pluginCatalog.directoryCatalog(一個真實的目錄目錄,而不是我創建的目錄)。由於DC實現INotifyComposablePartCatalogChanged我很困惑,爲什麼DC沒有發現新文件,即使我用新路徑創建一個新DC。我得到的變化通知是相關的,但A)與我目前的實現(我剛剛描述),然後改變通知是通過MEF DC和B)實現有什麼地方做什麼來實現你自己的通知監聽器會這樣工作嗎? – user64718 2010-04-13 13:46:59

0

我相信MEF只能加載相同組件的一個版本(我想在Silverlight中雖然)

1

我有一個類似的發出─複製發現插件應用程序的目錄後,一DirectoryCatalog止跌即使在打電話給.refresh()之後,他們也不會看到他們e DirectoryCatalog。

我發現單步執行代碼解決了這個問題 - 我最好的猜測是,在MEF掃描新程序集之前FileSystemWatcher啓動它的通知之後,文件系統仍然需要一些時間(可能會完成一些模糊的複製操作),並且看到裏面的零件。

System.Threading.Thread.Sleep(1000),跛腳,解決了這個問題。