插件热加载 - Snet Docs

🔌 PluginOperate — 插件热加载

命名空间: Snet.Core.plugin | 继承: CoreUnify<PluginOperate, string> | 源码: Snet.Core/plugin/

基于 AssemblyLoadContextisCollectible = true)实现运行时插件加载/卸载。支持 DLL 热插拔,无需重启应用。

PluginOperate API

插件发现与加载

// 扫描目录并初始化插件
public List<(PluginModel Model, object? Param)> InitPlugin(string path, string interfaceFullName)
public async Task<List<(PluginModel Model, object? Param)>> InitPluginAsync(...)

// 按 className 创建插件实例
public async Task<T?> CreateAsync<T>(string className, string param, PluginType type)

查询

public int LoadedPluginCount                  // 已加载插件数
public IReadOnlyCollection<string> LoadedPluginNames  // 已加载插件名列表
public bool IsPluginLoaded(string className)          // 检查是否已加载
public string GetPluginPath(string className)         // 获取插件路径
public string GetVersion(string className)            // 获取版本
public string GetPluginDiagnostics(string className)  // 获取诊断信息

获取插件对象

public T? GetPluginInterfaceObject<T>(string className) where T : class
public object? GetPluginParamObject(string interfaceFullName, string className)
public object? ConvertPluginJsonParam(string className, string jsonContent)

卸载

public async Task<bool> RemovePluginAsync(string className, CancellationToken token)
public async Task RemovePluginsAsync(CancellationToken token)  // 卸载全部

验证

public async Task<OperateResult> StatusVerifyAsync(string interfaceFullName,
    string className, string data, CancellationToken token)

PluginLoadContext — 插件加载上下文

内部类 | 继承: AssemblyLoadContext

public PluginLoadContext(string pluginPath, long maxAssemblySizeBytes = 50 * 1024 * 1024)
public int LoadedAssemblyCount
public Assembly LoadFromFileStream(string assemblyPath)
public async Task<Assembly> LoadFromFileStreamAsync(string assemblyPath, CancellationToken token)
public bool IsFullyUnloaded()  // 检查 ALC 是否已完全卸载

关键设计

  • isCollectible = true — 允许 GC 回收整个 ALC
  • 内存流加载 — 无文件锁
  • 大小限制 50MB — 防止恶意超大程序集
  • 路径沙箱 — 尾部分隔符验证,防止路径穿越

使用模式

var plugin = new PluginOperate();

// 1. 初始化 — 扫描 plugins/ 目录,加载所有 IDaq 实现
var plugins = plugin.InitPlugin("./plugins", "Snet.Model.interface.IDaq");

// 2. 获取插件实例
var siemensPlugin = plugin.GetPluginInterfaceObject<IDaq>("SiemensOperate");

// 3. 通过 JSON 配置创建
var instance = await plugin.CreateAsync<IDaq>("SiemensOperate",
    "{\"IpAddress\":\"192.168.1.100\",\"Port\":102}", PluginType.Daq);

// 4. 卸载
await plugin.RemovePluginAsync("SiemensOperate");

参见