MEF和ShadowCopying DLL,以便我可以在运行时覆盖它们

时间:2012-09-26 01:22:19

标签: c# mef appdomain shadow-copy

我试图阻止我的应用程序在我的MEF插件目录中锁定DLL,以便我可以在运行时覆盖程序集(注意我实际上并没有尝试让MEF在运行时重新加载它们,在下一个应用程序启动时很好,我只是不想要停止应用程序来复制)

我试图通过为我的mef加载的程序集创建一个阴影复制的应用程序域来执行此操作,如下所示:

[Serializable]
    public class Composer:IComposer
    {
        private readonly string _pluginPath;
        public Composer(IConfigurePluginDirectory pluginDirectoryConfig)
        {
            _pluginPath = pluginDirectoryConfig.Path;
            var setup = new AppDomainSetup();
            setup.ShadowCopyFiles = "true"; // really??? is bool not good enough for you?
            var appDomain = AppDomain.CreateDomain(AppDomain.CurrentDomain.FriendlyName + "_PluginDomain", AppDomain.CurrentDomain.Evidence, setup);

            appDomain.DoCallBack(new CrossAppDomainDelegate(DoWorkInShadowCopiedDomain));      
        }

        private void DoWorkInShadowCopiedDomain()
        {
            // This work will happen in the shadow copied AppDomain.

            var catalog = new AggregateCatalog();
            var dc = new DirectoryCatalog(_pluginPath);
            catalog.Catalogs.Add(dc);
            Container = new CompositionContainer(catalog);
        }

        public CompositionContainer Container { get; private set; }
    }

然后通过此类的CompositionContainer访问我的MEF组件目录。但是,组合容器似乎只在shadowcopy域内初始化(这是有意义的),这意味着它在我的应用程序域中为null。我只是想知道是否有更好的方法来做这个或某种方式来跨域查询来获取我的MEF组件

3 个答案:

答案 0 :(得分:3)

如果您不想遵循Dan Bryant和zync的解决方案,您可以创建一个shell应用程序,只需在新的AppDomain中执行您的应用程序。

方法是:

  1. 创建一个新的应用程序项目,它将是shell应用程序。
  2. 在shell应用程序中,创建AppDomain,启用卷影复制,如果需要,请指定启用卷影复制的目录。
  3. 使用AppDomain.ExecuteAssembly来调用当前的应用程序。
  4. 如果您拥有类库而不是应用程序,则可以尝试以下操作:

    1. 创建一个新的类库项目。
    2. 将以下界面添加到新的类库项目中:

      public interface IRemoteLoader  
      {  
          void Load();  
          void Unload();  
      }
      
    3. 将此接口的实现添加到需要在新AppDomain中执行的类库中。在LoadUnload方法中,您应该添加代码以分别执行初始化和清理。使类派生自MarshalByRefObject。这是.NET Remoting在两个AppDomains上创建代理对象所必需的。

    4. 创建新的AppDomain后,使用CreateInstanceAndUnwrap从步骤3创建加载器类的实例。

    5. 对从步骤4创建的对象使用LoadUnload

    6. 如果你没有细粒度的控制,只需启动/停止就足够了。

答案 1 :(得分:-1)

此方案更接近移动应用中的自动更新功能。基本上,如果在应用程序启动/重新启动时可用,则需要选择新的程序集。

设计此方法的一种方法可能是建立一种通信机制,以便在启动时向您的应用程序发出新程序集可用的信号(可能是version.txt文件)。如果是,则相同的version.txt文件可以指向程序集的新位置。是的 - 您可能最终创建了许多子文件夹以指向正确的版本,但这些可以由其他进程清理。

您可以使用像这样的层次结构 -

版\   - 版本1.0 \   - Version2.0 \

这种类型的设计更接近于众所周知的自动更新范例。

答案 2 :(得分:-2)

您是否可以选择不使用DirectoryCatalog并使用AssemblyCatalog加载目录中的所有程序集?您甚至可以转到代码plex并从DirectoryCatalog类中复制相同的代码,该类读取目录并加载程序集。

你会失去动态加载它们的能力,但正如你所提到的那样,这并非真正的要求。