2012-10-31 130 views
0

我有一个应用程序通过MEF加载插件。MEF程序集从缓存中加载?

应用程序正在终端服务器上的多个实例中运行。

当我需要在生产环境中测试新插件时,我将MEF重定向到另一个文件夹。 问题是,即使在重定向之后,组件也会从原始文件夹加载。 它不会每次都发生,我无法在我的机器上重现它。我怀疑这是某种缓存问题。

的MEF加载代码看起来是这样的:

using (var catalog = new AggregateCatalog()) { 

    Console.WriteLine("Loading components from {0}", folder); 

    catalog.Catalogs.Add(new DirectoryCatalog(folder, "*.dll")); 

    using (var container = new CompositionContainer(catalog)) { 
     try { 
      container.ComposeParts(this); 
     } 
     catch (ReflectionTypeLoadException ex) { 
      foreach (var loaderException in ex.LoaderExceptions) { 
       // log loading error 
    } 
} 

foreach (var assembly in _allComponents.GroupBy(x => x.GetType().Assembly)) { 
    Console.WriteLine("Loaded from {0}", assembly.Key.CodeBase); 
} 

从代码的结果是上面的样子

Loading components from C:\NewPlugins 
Loaded from C:\OldPlugins 
+0

难道你在两个目录中都有相同标识的程序集吗?如果是这样,只需创建一个插件更新,就可以使您的程序集具有强大的名称并增加版本。 –

+0

是的,当然他们有相同的身份。如果这是问题,我认为'DirectoryCatalog'是一个坏名字,因为它通过身份加载程序集,而不是从目录加载。 – adrianm

回答

0

因为,根据您的意见,您有与两个目录组件相同的身份,上面代码的输出是正常的。这不是DirectoryCatalog的问题。它会尝试从特定目录加载程序集,但如果具有相同标识的程序集已加载到当前的AppDomain中,则CLR将不加载该程序集。从集会的地点来看,无关紧要,重要的是身份。

解决的办法是让你的程序集有强大的名字,并在创建插件更新时增加版本。这样,NewPlugins目录中的程序集将具有与已从OldPlugins目录中加载的目录不同的身份。

如果您有兴趣了解如何加载程序集,请查看有关程序集加载的Suzanne Cook's blog条目。

+0

我知道程序集是如何加载的。正如你所说,我的解释是,CLR只考虑加载在相同appdomain中的程序集的身份(因此无法加载具有相同身份的两个不同程序集)。 OldPlugins中的程序集仅由同一台计算机上完全不同的应用程序加载,因此显然身份查找是跨应用程序域。 (仍然认为这是DirectoryCatalog的问题,它应该强制从目录加载) – adrianm

+0

@adrianm使用Assembly.LoadFile可以从不同位置加载具有相同身份的两个程序集。但DirectoryCatalog使用Assembly.Load(AssemblyName)。 CLR加载程序集的方式非常复杂。每当我读到它,似乎我第一次理解了一些东西。我不确定你对不同应用程序的含义。我以为你试图在同一AppDomain上加载两个版本。您是否使用gacutil在GAC上安装这些程序集? –

+0

我在OldPlugins文件夹中的服务器上运行了一个应用程序实例。现在我将更新版本的应用程序和/或插件放在同一台服务器上的NewPlugins文件夹中(例如测试新功能)。当我启动更新的应用程序时,它仍然从OldPlugins文件夹加载程序集。没有涉及GAC。我只是将DirectoryCatalog指向应用程序的启动文件夹。 – adrianm