Some checks failed
Create and publish a Docker image / Publish image (push) Failing after 4m3s
64 lines
2.4 KiB
C#
64 lines
2.4 KiB
C#
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);
|
||
}
|
||
} |