Как загрузить плагины в .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 и следующие методы:
Сначала вы загружаете сборку по этому пути, затем получаете от него тип (класс) по имени, затем снова возвращаете метод класса по имени и, наконец, вызываете метод с соответствующими параметрами.
Ответ 7
Статья немного старше, но все еще применима для создания уровня расширяемости в вашем приложении:
Разрешить пользователям добавлять функциональность в ваши .NET-приложения с помощью макросов и подключаемых модулей