Плагин MEF + не обновляется - PullRequest
4 голосов
/ 13 апреля 2010

Я уже спрашивал об этом на форуме MEF Codeplex, но пока не получил ответа, поэтому решил, что попробую StackOverflow. Вот оригинальный пост, если кому-то интересно (это всего лишь его копия):

MEF Codeplex

«Позвольте мне сначала сказать, что я совершенно новичок в MEF (только что обнаружил его сегодня) и до сих пор очень доволен им. Однако я столкнулся с проблемой, которая очень расстраивает. Я создаю приложение, которое будет иметь архитектуру плагинов и плагины будут храниться только в одном файле DLL (или закодированы в основное приложение). Файл DLL должен быть в состоянии перекомпилироваться во время выполнения, и приложение должно распознавать это и перезагрузите плагины (я знаю, что это сложно, но это требование). Для этого я воспользовался подходом, описанным здесь http://blog.maartenballiauw.be/category/MEF.aspx (ищите WebServerDirectoryCatalog). По сути, идея состоит в том, чтобы "отслеживать папку плагинов, Скопируйте новые / измененные сборки в папку / bin веб-приложения и проинструктируйте MEF загрузить их экспорт оттуда. "Это мой код, который, вероятно, не является правильным способом сделать это, но это то, что я нашел в некоторых примерах в сети :

        main()...
    string myExecName = Assembly.GetExecutingAssembly().Location;
        string myPath = System.IO.Path.GetDirectoryName(myExecName);
        catalog = new AggregateCatalog();
        pluginCatalog = new MyDirectoryCatalog(myPath + @"/Plugins");
        catalog.Catalogs.Add(pluginCatalog);


        exportContainer = new CompositionContainer(catalog);

        CompositionBatch compBatch = new CompositionBatch();
        compBatch.AddPart(this);
        compBatch.AddPart(catalog);
        exportContainer.Compose(compBatch);

и

    private FileSystemWatcher fileSystemWatcher;
    public DirectoryCatalog directoryCatalog;
    private string path;
    private string extension;

    public MyDirectoryCatalog(string path)
    {
        Initialize(path, "*.dll", "*.dll");
    }

    private void Initialize(string path, string extension, string modulePattern)
    {
        this.path = path;
        this.extension = extension;
        fileSystemWatcher = new FileSystemWatcher(path, modulePattern);
        fileSystemWatcher.Changed += new FileSystemEventHandler(fileSystemWatcher_Changed);
        fileSystemWatcher.Created += new FileSystemEventHandler(fileSystemWatcher_Created);
        fileSystemWatcher.Deleted += new FileSystemEventHandler(fileSystemWatcher_Deleted);
        fileSystemWatcher.Renamed += new RenamedEventHandler(fileSystemWatcher_Renamed);
        fileSystemWatcher.IncludeSubdirectories = false;
        fileSystemWatcher.EnableRaisingEvents = true;
        Refresh();
    }
    void fileSystemWatcher_Renamed(object sender, RenamedEventArgs e)
    {
        RemoveFromBin(e.OldName);
        Refresh();
    }
    void fileSystemWatcher_Deleted(object sender, FileSystemEventArgs e)
    {
        RemoveFromBin(e.Name);
        Refresh();
    }
    void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
    {
        Refresh();
    }
    void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        Refresh();
    }
    private void Refresh()
    {
        // Determine /bin path 
        string binPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
        string newPath = "";
        // Copy files to /bin 
        foreach (string file in Directory.GetFiles(path, extension, SearchOption.TopDirectoryOnly))
        {
            try
            {
                DirectoryInfo dInfo = new DirectoryInfo(binPath);
                DirectoryInfo[] dirs = dInfo.GetDirectories();
                int count = dirs.Count() + 1;
                newPath = binPath + "/" + count;
                DirectoryInfo dInfo2 = new DirectoryInfo(newPath);
                if (!dInfo2.Exists)
                    dInfo2.Create();

                File.Copy(file, System.IO.Path.Combine(newPath, System.IO.Path.GetFileName(file)), true);
            }
            catch
            {
                // Not that big deal... Blog readers will probably kill me for this bit of code :-) 
            }
        }
        // Create new directory catalog 
        directoryCatalog = new DirectoryCatalog(newPath, extension);
        directoryCatalog.Refresh();
    }
    public override IQueryable<ComposablePartDefinition> Parts
    {
        get { return directoryCatalog.Parts; }
    }
    private void RemoveFromBin(string name)
    {
        string binPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "");
        File.Delete(Path.Combine(binPath, name));
    }

Так что все это на самом деле работает, и после окончания кода в главной переменной mynnumerable фактически заполняется всеми плагинами в DLL (которая, если вы следуете коду, находится в Plugins / 1, так что я могу изменить DLL в папке плагинов). Так что теперь у меня должна быть возможность перекомпилировать DLL плагинов, поместить ее в папку плагинов, мой FileWatcher обнаружит, что она изменилась, и затем скопировать ее в папку «2», а directoryCatalog должен указать новую папку. Все это на самом деле работает! Проблема в том, что, хотя кажется, что все указано правильно, моя переменная IEnumerable никогда не обновляется новыми плагинами. Так близко, но пока так далеко! Какие-либо предложения? Я знаю недостатки этого, что на самом деле никакая dll не выгружается и не вызывает утечку памяти, но это приложение для Windows, и, вероятно, оно будет запускаться хотя бы раз в день, а плагины вряд ли изменятся. это часто, но все равно от клиента требуется, чтобы он делал это без перезагрузки приложения. Спасибо!

Спасибо за любую помощь, которую вы все можете оказать, это сводит меня с ума от невозможности понять это. "

Ответы [ 3 ]

3 голосов
/ 13 апреля 2010

Нет триггера для перекомпоновки, потому что ваша реализация каталога не предоставляет уведомлений. Реализуйте INotifyComposablePartCatalogChanged , чтобы исправить это.

1 голос
/ 11 августа 2011

У меня была похожая проблема - после копирования обнаруженных плагинов в каталог приложения, DirectoryCatalog не будет их видеть, даже после вызова .refresh () в DirectoryCatalog.

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

System.Threading.Thread.Sleep (1000), как бы неубедительно, решил проблему.

1 голос
/ 13 апреля 2010

Я считаю, что MEF может загрузить только одну версию той же сборки (хотя я пробовал на Silverlight)

...