Как загрузить плагины в .NET?
-
08-06-2019 - |
Вопрос
Я хотел бы предоставить какой-нибудь способ создания динамически загружаемых плагинов в моем программном обеспечении.Типичный способ сделать это - использовать Загружаемая библиотека Функция WinAPI для загрузки библиотеки dll и вызова Получитьprocaddress чтобы получить указатель на функцию внутри этой библиотеки dll.
Мой вопрос заключается в том, как мне динамически загружать плагин в приложение C # / .Net?
Решение
Следующий фрагмент кода (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.
Другие советы
Начиная с .NET 3.5, существует формализованный, встроенный способ создания и загрузки плагинов из приложения .NET.Все дело в Система.Добавление пространство имен.Для получения дополнительной информации вы можете ознакомиться с этой статьей на MSDN: Надстройки и расширяемость
Динамически Загружаемые плагины
Дополнительные сведения о том, как динамически загружать сборки .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) для создания подключаемого модуля framework.
Существующие фреймворки подключаемых модулей
Я знаю о двух подключаемых фреймворках:
- Mono.Надстройки - Как упоминалось в это ответ на другой вопрос.
- Платформа управляемых надстроек (MAF) - Это тот самый
System.AddIn
пространство имен как упомянуто Мэттом в его ответе.
Некоторые люди говорят о Платформа управляемой расширяемости (MEF) как подключаемый модуль или надстройка, которой он не является.Для получения дополнительной информации см. этот StackOverflow.com вопрос и этот StackOverflow.com вопрос.
Один из советов - загрузить все плагины и тому подобное в собственный домен приложения, поскольку запущенный код может быть потенциально вредоносным.Собственный домен приложения также можно использовать для "фильтрации" сборок и типов, которые вы не хотите загружать.
AppDomain domain = AppDomain.CreateDomain("tempDomain");
И загрузить сборку в домен приложения:
AssemblyName assemblyName = AssemblyName.GetAssemblyName(assemblyPath);
Assembly assembly = domain.Load(assemblyName);
Чтобы выгрузить домен приложения:
AppDomain.Unload(domain);
Да, ++ Мэтту и System.Дополнение (статья в журнале MSDN magazine из двух частей о System.Дополнения доступны здесь и здесь).Другая технология, на которую вы, возможно, захотите взглянуть, чтобы получить представление о том, куда может пойти .NET Framework в будущем, - это Платформа управляемой Расширяемости в настоящее время доступен в форме CTP на Codeplex.
В принципе, вы можете сделать это двумя способами.
Первый - импортировать 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);
Второй способ - сделать это .СЕТЕВЫМ способом:используя отражение.Проверьте систему.Пространство имен отражения и следующие методы:
- Сборка.Загрузочный файл
- Сборка.Полученный тип
- Сборка.Исходные типы
- Введите.GetMethod
- MethodInfo.Вызвать
Сначала вы загружаете сборку по ее пути, затем получаете из нее тип (класс) по его имени, затем снова получаете метод класса по его имени и, наконец, вызываете метод с соответствующими параметрами.
Статья немного старше, но все еще применима для создания уровня расширяемости в вашем приложении: