Как загрузить плагины в .NET?

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

У меня вопрос, как мне динамически загрузить плагин в C # /. Net приложении?

18.08.2008 07:34:56
8 ОТВЕТОВ
РЕШЕНИЕ

Следующий фрагмент кода (C #) создает экземпляр любых конкретных классов, полученных из Baseнайденных в библиотеках классов (* .dll) в пути приложения, и сохраняет их в списке.

using System.IO;
using System.Reflection;

List<Base> objects = new List<Base>();
DirectoryInfo dir = new DirectoryInfo(Application.StartupPath);

foreach (FileInfo file in dir.GetFiles("*.dll"))
{
    Assembly assembly = Assembly.LoadFrom(file.FullName);
    foreach (Type type in assembly.GetTypes())
    {
        if (type.IsSubclassOf(typeof(Base)) && type.IsAbstract == false)
        {
            Base b = type.InvokeMember(null,
                                       BindingFlags.CreateInstance,
                                       null, null, null) as Base;
            objects.Add(b);
        }
    }
}

Изменить: классы, на которые ссылается Мэтт , вероятно, лучший вариант в .NET 3.5.

20
23.05.2017 12:25:06

В основном вы можете сделать это двумя способами.

Первый - импортировать kernel32.dll и использовать LoadLibrary и GetProcAddress, как вы использовали это ранее:

[DllImport("kernel32.dll")]

internal static extern IntPtr LoadLibrary(String dllname);

[DllImport("kernel32.dll")]

internal static extern IntPtr GetProcAddress(IntPtr hModule, String procname);

Второе - сделать это .NET-способом: с помощью отражения. Проверьте пространство имен System.Reflection и следующие методы:

Сначала вы загружаете сборку по ее пути, затем извлекаете тип (класс) из нее по имени, затем снова получаете метод класса по его имени и, наконец, вызываете метод с соответствующими параметрами.

3
18.08.2008 07:44:55

Начиная с .NET 3.5 существует формализованный, запеченный способ создания и загрузки плагинов из приложения .NET. Это все в пространстве имен System.AddIn . Для получения дополнительной информации вы можете проверить эту статью на MSDN: надстройки и расширяемость

28
18.08.2008 08:07:21

Одним из советов является загрузка всех плагинов и тому подобного в собственный домен приложений, поскольку выполняемый код может быть потенциально вредоносным. Собственный домен приложения также можно использовать для «фильтрации» сборок и типов, которые вы не хотите загружать.

AppDomain domain = AppDomain.CreateDomain("tempDomain");

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

AssemblyName assemblyName = AssemblyName.GetAssemblyName(assemblyPath);
Assembly assembly = domain.Load(assemblyName);

Чтобы выгрузить домен приложения:

AppDomain.Unload(domain);
5
18.08.2008 08:09:40

Эта статья немного старше, но все же применима для создания слоя расширяемости в вашем приложении:

Позвольте пользователям добавлять функциональность в ваши приложения .NET с помощью макросов и плагинов

2
18.08.2008 18:32:17
Хм, ссылка, к сожалению, перестала существовать, что не так плохо, как могло бы быть, поскольку вы включили заголовок, но, тем не менее, я не нахожу его в быстром Google :-(
SamB 10.09.2015 21:44:44

Да, ++ для Matt и System.AddIn (статья журнала MSDN из двух частей о System.AddIn доступна здесь и здесь ). Еще одна технология, на которую вы, возможно, захотите взглянуть, чтобы получить представление о том, что может произойти в будущем .NET Framework, - это платформа Managed Extensibility Framework, которая в настоящее время доступна в форме CTP в Codeplex.

4
9.09.2008 22:03:07

Динамически загружаемые плагины

Информацию о том, как динамически загружать сборки .NET, смотрите в этом вопросемой ответ ). Вот некоторый код для загрузки создания AppDomainи загрузки сборки в него.

var domain = AppDomain.CreateDomain("NewDomainName");
var pathToDll = @"C:\myDll.dll"; 
var t = typeof(TypeIWantToLoad);
var runnable = domain.CreateInstanceFromAndUnwrap(pathToDll, t.FullName) 
    as IRunnable;
if (runnable == null) throw new Exception("broke");
runnable.Run();

Разгрузочные плагины

Типичное требование инфраструктуры плагинов - выгрузить плагины. Чтобы выгрузить динамически загруженные сборки (например, плагины и надстройки), вы должны выгрузить содержимое AppDomain. Для получения дополнительной информации см. Эту статью на MSDN по разгрузке доменов приложений .

Использование WCF

Существует вопрос и ответ о переполнении стека, которые описывают, как использовать Windows Communication Framework (WCF) для создания инфраструктуры плагинов.

Существующие плагины

Я знаю о двух плагинах:

Некоторые люди говорят о Managed Extensibility Framework (MEF) как о плагине или надстройке, но это не так. Для получения дополнительной информации см. Этот вопрос StackOverflow.com и этот вопрос StackOverflow.com .

8
23.05.2017 11:53:23

Это моя реализация, вдохновленная этим кодом, избегая перебора всех сборок и всех типов (или, по крайней мере, фильтрации с помощью linQ). Я просто загружаю библиотеку и пытаюсь загрузить класс, который реализует общий общий интерфейс. Просто и быстро :)

Просто объявите интерфейс в отдельной библиотеке и назовите его как в вашей системе, так и в вашем плагине:

public interface IYourInterface
{
    Task YourMethod();
}

В вашей библиотеке плагинов объявите класс, который реализует IYourInterface

public class YourClass: IYourInterface
{
    async Task IYourInterface.YourMethod()
    {
        //.....
    }
}

В вашей системе объявите этот метод

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Linq;

public abstract class ReflectionTool<TSource> where TSource : class
{
    public static TSource LoadInstanceFromLibrary(string libraryPath)
    {
        TSource pluginclass = null;
        if (!System.IO.File.Exists(libraryPath))
            throw new Exception($"Library '{libraryPath}' not found");
        else
        {
            Assembly.LoadFrom(libraryPath);

            var fileName = System.IO.Path.GetFileName(libraryPath).Replace(".dll", "");
            var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(c => c.FullName.StartsWith(fileName));
            var type = assembly.GetTypes().FirstOrDefault(c => c.GetInterface(typeof(TSource).FullName) != null);

            try
            {
                pluginclass = Activator.CreateInstance(type) as TSource;
            }
            catch (Exception ex)
            {
                LogError("", ex);
                throw;
            }
        }

        return pluginclass;
    }
}

И назовите это так:

IYourInterface instance = ReflectionTool<IYourInterface>.LoadInstanceFromLibrary("c:\pathToYourLibrary.dll");
0
2.01.2020 23:17:34