MEF и ShadowCopying DLL, чтобы я мог перезаписать их во время выполнения

Я пытаюсь остановить приложение блокировки DLL в моем каталоге плагинов MEF, чтобы я мог перезаписывать сборки во время выполнения (обратите внимание, что я на самом деле не пытаюсь перезагрузить 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; }
    }

а затем получить доступ к моему каталогу компонентов MEF через CompositionContainer этого класса. Однако контейнер состава кажется инициализированным только внутри области shadowcopy (что имеет смысл), а это значит, что его нуль в моем домене приложения. Я просто задавался вопросом, есть ли лучший способ сделать это или каким-то образом перекрещивать запрос домена, чтобы получить мои компоненты MEF.

Ответ 1

Если вы не хотите следовать решению от Dan Bryant и zync, вы можете создать приложение оболочки, которое просто выполнит ваше приложение в новом AppDomain.

Подход:

  • Создайте новый проект приложения, который будет оболочкой.
  • В приложении оболочки создайте AppDomain, включите теневое копирование и, если хотите, укажите каталог, в котором будет включено теневое копирование.
  • Используйте AppDomain.ExecuteAssembly для вызова вашего текущего приложения.

Если вместо приложения у вас есть библиотека классов, вы можете попробовать следующее:

  • Создайте новый проект библиотеки классов.
  • Добавьте следующий интерфейс в новый проект библиотеки классов:

    public interface IRemoteLoader  
    {  
        void Load();  
        void Unload();  
    }
    
  • Добавьте реализацию этого интерфейса в библиотеку классов, которая должна быть выполнена в новом AppDomain. В методах Load и Unload вы должны добавить код для выполнения инициализации и очистки соответственно. Сделайте класс из MarshalByRefObject. Это необходимо для .NET Remoting для создания прокси-объектов на обоих AppDomains.

  • После создания нового AppDomain используйте CreateInstanceAndUnwrap, чтобы создать экземпляр класса загрузчика с шага 3.

  • Используйте Load и Unload для объекта, созданного с шага 4.

Этого будет достаточно, если вы не используете мелкозернистый контроль и достаточно просто запустить/остановить.

Ответ 2

Этот сценарий ближе к функции автоматического обновления в мобильных приложениях. По сути, вы хотите собрать новые сборки, если они доступны в приложении Start/Restart.

Одним из способов разработки этого может быть наличие механизма связи для подачи сигнала в ваше приложение при запуске новых сборок (возможно, файла version.txt). Если да, то тот же файл version.txt может указывать на новое расположение сборок. Да - вы можете создать несколько подпапок, чтобы указать на правильную версию, но они могут быть очищены другим процессом.

вы можете использовать иерархическую структуру, например:

Версия \  - Версия1.0 \  - Version2.0\

Этот тип дизайна будет ближе к хорошо знакомой парадигме автоматического обновления.

Ответ 3

Есть ли у вас возможность не использовать DirectoryCatalog и использовать AssemblyCatalog для загрузки всех сборок в каталоге? Вы даже можете пойти в код plex и скопировать тот же код из класса DirectoryCatalog, который читает через каталог и загружает сборки.

Вы потеряли бы способность загружать их на лету, но, как вы упомянули, это не требование.