Использование MEF для загрузки DLL со встроенными библиотеками

В настоящее время я пишу набор приложений с системой плагинов, которая загружает плагины во время выполнения с использованием инфраструктуры MEF.

В настоящее время я настроил одно из моих приложений WPF верхнего уровня для встраивания ссылочных DLL-файлов в качестве встроенных ресурсов и загрузки их во время выполнения, используя метод, описанный здесь.

Это отлично работает, и я получаю мое приложение WPF с одним файлом, которое работает нормально.

Тем не менее, другое из моих консольных приложений верхнего уровня использует платформу MEF для загрузки плагинов во время выполнения (приложение WPF исправлено и явно включает в себя плагины). Мои плагины сами имеют несколько зависимостей от различных библиотек, и папка расширений, из которой консольное приложение загружает плагины, завалена всеми различными библиотеками библиотеки.

Я хотел бы встроить зависимости каждого плагина в себя так, чтобы мой каталог расширений содержал только файлы DLL верхнего уровня. Метод, который я использовал выше, не удовлетворяет этому подходу, поскольку компонент плагина не может найти требуемую зависимость, поскольку только встроенная сборка ищет эти встроенные ресурсы.

Мой текущий метод OnResolveAssembly выглядит так:

public static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    var assemblyName = new AssemblyName(args.Name);

    string path = assemblyName.Name + ".dll";
    if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false)
    {
        path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);
    }

    using (Stream stream = executingAssembly.GetManifestResourceStream(path))
    {
        if (stream == null)
            return null;

        var assemblyRawBytes = new byte[stream.Length];
        stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);

        return Assembly.Load(assemblyRawBytes);
    }
}

Я думаю, что лучший способ продолжить это добавить функциональность для отслеживания всех сборок, загруженных в список, и как только новая сборка будет загружена таким образом, рекурсивно сделайте то же самое; загружать любые встроенные библиотеки DLL в тех, которые вы идете. Затем вы можете добавить эти библиотеки DLL в список, который будет действовать как кеш.

Возможно, есть лучший способ продолжить это?

1 ответ

Я реализовал очень похожее решение для вас, и оно работает очень хорошо для меня. Как видите, я отслеживаю уже загруженные сборки в _references толковый словарь.

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

public static class ApplicationHost
{
    private static readonly Dictionary<string, Assembly> _references = new Dictionary<string, Assembly>();

    [STAThread]
    private static void Main()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => _references.ContainsKey(args.Name) ? _references[args.Name] : null;
        RegisterAssemblyAndEmbeddedDependencies();
        // continue application bootstrapping...
    }

    public static void RegisterAssemblyAndEmbeddedDependencies()
    {
        var assembly = Assembly.GetCallingAssembly();
        _references[assembly.FullName] = assembly;
        foreach (var resourceName in assembly.GetManifestResourceNames())
        {
            using (var resourceStream = assembly.GetManifestResourceStream(resourceName))
            {
                var rawAssembly = new byte[resourceStream.Length];
                resourceStream.Read(rawAssembly, 0, rawAssembly.Length);
                var reference = Assembly.Load(rawAssembly);
                _references[reference.FullName] = reference;
            }
        }
    }
}
Другие вопросы по тегам