关于c#:MEF和ShadowCopying DLL,以便我可以在运行时覆盖它们

MEF and ShadowCopying DLLs so that I can overwrite them at runtime

我正在尝试停止我的应用程序锁定在我的mef插件目录中的dll,以便我可以在运行时覆盖程序集(注意,我并不是真的尝试让mef在运行时重新加载它们,在下一个应用程序启动时是好的,我只是不想停止应用程序来进行复制)

我尝试通过如下方式为我的MEF加载程序集创建卷影复制的应用程序域来完成此操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[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域内初始化(这很有意义),这意味着它在我的应用程序域中为空。我只是想知道有没有更好的方法来完成这个任务,或者有什么方法可以跨域查询来获取我的MEF组件


如果您不想遵循丹·布莱恩特和zync的解决方案,您可以创建一个shell应用程序,它只在新的AppDomain中执行您的应用程序。

一种方法是:

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

  • 创建新的类库项目。
  • 将以下接口添加到新类库项目:

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

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

  • 在步骤4创建的对象上使用LoadUnload

  • 如果您不进行细粒度控制,仅仅启动/停止就足够了,那么这就足够了。


    这种情况更接近于移动应用程序中的自动更新功能。基本上,如果在应用程序启动/重新启动时可用,您希望获取新的程序集。

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

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

    版本-版本1.0-版本2.0

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


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

    您将失去在飞行中加载它们的能力,但正如您提到的,这并不是真正的需求。