Вызов Refresh () для DirectoryCatalog создает исключение ChangeRejectedException, если в каталоге обнаружены новые библиотеки DLL. - PullRequest
8 голосов
/ 15 июля 2009

Я экспериментирую с MEF и создал тестовую программу для вызова "плагинов", которые реализуют некоторый данный интерфейс, а именно:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProbeContract
{
    public interface IProbe
    {
        int DoProbe(string what);
        List<string> GetCapabilities();
    }
}

Я создал пример консольной программы, которая загружает «плагины» из собственной сборки и, если таковые имеются, из директории, в которую помещаются дополнительные библиотеки DLL. Программа работает нормально, независимо от того, является ли каталог плагинов пустым (называются только «родные» плагины), или у него есть совместимые библиотеки DLL для запуска. НО ... если новая DLL добавляется между итерациями цикла, метод Refresh () в DirectoryCatalog выдает исключение ChangeRejectedException, которое объясняется следующим образом:

Состав остается без изменений. изменения были отклонены из-за следующие ошибки: Композиция произвел единственную ошибку композиции. Основная причина приведена ниже. Просмотрите CompositionException.Errors недвижимость для более подробной информация.

1) Изменения в экспорте предотвращены не подлежащий возврату импорт «MEFTest.Program.ProberSet (ContractName = "ProbeContract.IProbe")» на части "MEFTest.Program".

Программа находится ниже, следуйте коду для DLL, которую я пытаюсь добавить. Что я делаю не так?

using System;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProbeContract;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

namespace MEFTest
{
    class Program
    {
        [ImportMany]
        IEnumerable<IProbe> ProberSet { get; set; }

        CompositionContainer exportContainer;
        DirectoryCatalog pluginCatalog;
        AggregateCatalog catalog;

        private void Run()
        {
            catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            string myExecName = Assembly.GetExecutingAssembly().Location;
            string myPath = Path.GetDirectoryName(myExecName);
            pluginCatalog = new DirectoryCatalog(myPath + "/Plugins");
            catalog.Catalogs.Add(pluginCatalog);
            exportContainer = new CompositionContainer(catalog);

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

            for (; ; )
            {
                Console.Write("Press any key to run all probes: ");
                Console.ReadKey(true);
                Console.WriteLine();
                pluginCatalog.Refresh();
                foreach (var Prober in ProberSet)
                {
                    Prober.DoProbe("gizmo");
                }
            }
        }

        static void Main(string[] args)
        {
            Program p = new Program();
            p.Run();
        }
    }
}

Плагин. Два других плагина схожи, с той лишь разницей, что они находятся в той же сборке, что и основная программа:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using ProbeContract;

namespace OtherProbes
{
    [Export(typeof(IProbe))]
    public class SpankyNewProber : IProbe
    {
        public int DoProbe(string what)
        {
            Console.WriteLine("I'm Spanky and New and I'm probing [{0}]", what);
            return 0;
        }

        public List<string> GetCapabilities()
        {
            List<string> retVal = new List<string>();
            retVal.Add("spanky");
            retVal.Add("new");
            return retVal;
        }
    }
}

1 Ответ

13 голосов
/ 16 июля 2009

Я предполагаю, что вы используете MEF preview 6, потому что вы видите исключения отклонения. Причина, по которой вы видите отклонение изменения, заключается в том, что ваш ProberSet не подлежит повторной компоновке. Попробуйте изменить импорт ProberSet на:

[ImportMany(AllowRecomposition=true)]        
IEnumerable<IProbe> ProberSet { get; set; }

Это позволит ввести новый экспорт IProbe в каталог / контейнер после того, как этот импорт уже составлен.

Идея заключается в том, что, как только вы получите стабильную композицию, мы отклоняем любые изменения, которые могут потенциально дестабилизировать эту композицию, и в вашем случае вы заявили, что хотите установить набор нерекомбируемых объектов IProbe, поэтому добавление новых IProbe после их первоначальной установки нарушать это требование.

...