Files
SfeduSchedule/SfeduSchedule/PluginLoader.cs
Sergey Karmanov fd1c033460
Some checks failed
Create and publish a Docker image / Publish image (push) Failing after 4m3s
Добавил систему плагинов
2025-09-07 15:47:25 +03:00

64 lines
2.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Reflection;
using System.Runtime.Loader;
using SfeduSchedule.Plugin.Abstractions;
public sealed record LoadedPlugin(IPlugin Instance, Assembly Assembly, PluginLoadContext Context);
public static class PluginLoader
{
// Загружаем все сборки *.plugin.dll из папки плагинов
public static IReadOnlyList<LoadedPlugin> LoadPlugins(string pluginsDir)
{
var result = new List<LoadedPlugin>();
if (!Directory.Exists(pluginsDir))
return result;
foreach (var file in Directory.EnumerateFiles(pluginsDir, "*.plugin.dll", SearchOption.AllDirectories))
{
var path = Path.GetFullPath(file);
var alc = new PluginLoadContext(path);
var asm = alc.LoadFromAssemblyPath(path);
// Ищем реализацию IPlugin
var pluginType = asm
.GetTypes()
.FirstOrDefault(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface);
if (pluginType is null)
continue;
var instance = (IPlugin)Activator.CreateInstance(pluginType)!;
result.Add(new LoadedPlugin(instance, asm, alc));
}
return result;
}
}
// Отдельный контекст загрузки для изоляции зависимостей плагина
public sealed class PluginLoadContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver _resolver;
public PluginLoadContext(string pluginMainAssemblyPath)
: base(isCollectible: true)
{
_resolver = new AssemblyDependencyResolver(pluginMainAssemblyPath);
}
// Разрешаем управляемые зависимости плагина из его папки.
// Возвращаем null, чтобы отдать решение в Default ALC для общих сборок (например, Plugin.Abstractions).
protected override Assembly? Load(AssemblyName assemblyName)
{
var path = _resolver.ResolveAssemblyToPath(assemblyName);
return path is null ? null : LoadFromAssemblyPath(path);
}
// Нативные зависимости (если есть)
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
var path = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
return path is null ? IntPtr.Zero : LoadUnmanagedDllFromPath(path);
}
}