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

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

Мой вопрос: как я могу динамически загружать плагин в С#/. Net-приложение?

Ответ 1

Следующий фрагмент кода (С#) создает экземпляр любых конкретных классов, полученных из 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);
        }
    }
}

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

Ответ 2

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

Ответ 3

Динамические загрузки плагинов

Информацию о том, как динамически загружать сборки .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 при разгрузке AppDomains.

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

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

Существующие модули плагинов

Я знаю две плагины:

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

Ответ 4

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

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

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

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

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

AppDomain.Unload(domain);

Ответ 5

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

Ответ 6

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

Во-первых, нужно импортировать файл 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 и следующие методы:

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