2013-04-22 55 views
10

MEF运行时插件更新问题

问题

我的MEF代码在运行时没有正确更新程序集,从与DirectoryCatalog关联的文件夹中更新程序集。插件在运行时加载成功,但是当我更新dll并在DirectoryCatalog上调用Refresh时,程序集没有得到更新。

背景

我正在构建一个具有MEF容器的dll,并使用DirectoryCatalog来查找本地插件文件夹。我目前从一个简单的WinForm中调用这个dll,这是安装到一个单独的项目使用ShadowCopy,所以我可以覆盖我的插件文件夹中的dll。我没有使用FileWatcher来更新这个文件夹,而是公开一个调用DirectoryCatalog刷新的公共方法,所以我可以随意更新程序集而不是自动更新。

代码

基类实例化MEF目录和容器,并将其保存为类变量引用访问后

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

} ... 

这里就是我试图覆盖插件。我的更新测试是将返回的响应输出到一个文本框,我更改插件返回的字符串,重建并将其复制到插件文件夹中。但它不会更新正在运行的应用程序,直到我关闭并重新启动应用程序。

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

编辑

import语句

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

研究

我在文章和代码示例的答案似乎是做了相当广泛的研究和无处不在,一个DirectoryCatalog添加到容器中,并保存该目录的引用,然后在该引用上调用Refresh,在添加了新插件后,它将更新程序集......我正在执行这些程序集,但它没有显示来自新插件dll的更新输出。

请求

有没有人看过这个问题,或者知道什么可能会导致我的问题,在运行时不更新的程序集?任何额外的信息或见解,将不胜感激。

决议

感谢Panos和Stumpy为他们的链接,这导致我的解决方案我的问题。对于未来的知识搜索者,我的主要问题是,当新程序集与覆盖的dll具有完全相同的程序集名称时,Refresh方法不会更新程序集。对于我的POC,我只是测试了重新生成日期附加到程序集名称和其他一切相同,它的工作就像一个魅力。他们在下面的评论中的链接非常有用,如果你有同样的问题,建议你这样做。

+1

DirectoryCatalog.Refresh会没有检测到更新的assebmlies。只有新的或删除的。看看这个答案解决方法和建议:http://stackoverflow.com/a/14842417/850119 – 2013-04-23 10:14:32

+0

我的dll被锁定时,他们被加载,所以我不能用新的dll覆盖它们。你没有这个问题吗?你做了什么让他们可以更新。 – 2013-12-18 11:18:55

+0

是的,我确实有这个问题。我提到的其中一个步骤是启用“Shadow Copy”。阴影复制允许程序拉取dll程序集的本地副本,并将它们添加到本地缓存中,而不是锁定dll。必须启用此功能才能在运行时“热插拔”dll,否则您需要停止该程序,更改dll,然后重新启动它。我认为这是我看的例子,但如果它不适合你谷歌MEF和影子副本,http://stackoverflow.com/questions/12593308/mef-and-shadowcopying-dlls-so-that-i -can-over-them-at-runtime – Madullah 2014-02-04 01:36:51

回答

3

您是否为您的Import attribut设置了AllowRecomposition参数?

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

编辑:

DirectoryCatalog不更新组件,只有添加或删除: http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.hosting.directorycatalog.refresh.aspx

对周围的工作: https://stackoverflow.com/a/14842417/2215320

+0

我做到了,对不起,我原本没有发布import语句代码,我已经更新了问题以反映我的import语句。 – Madullah 2013-04-23 13:33:04

+0

和你的刷新代码?我认为问题在里面。你说没有使用FileSystemWatcher,你如何检测并重新加载你的程序集? – Niels 2013-04-23 17:56:41

+0

我通过上面看到的RefreshCatalog方法公开它。我从winForm上的按钮单击事件调用该方法。 – Madullah 2013-04-23 19:12:12