using Serein.Library; using Serein.Library.Api; using Serein.Library.FlowNode; using Serein.Library.Utils; using Serein.NodeFlow.Model.Library; using Serein.NodeFlow.Tool; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; namespace Serein.NodeFlow.Services { /// /// 管理加载在运行环境中的外部程序集 /// public class FlowLibraryService { public FlowLibraryService(IFlowEnvironment flowEnvironment) { this.flowEnvironment = flowEnvironment; } private readonly IFlowEnvironment flowEnvironment; /// /// 缓存流程依赖 /// private readonly ConcurrentDictionary _flowLibraryCaches = new ConcurrentDictionary(); private readonly ConcurrentDictionary _flowLibraryAssemblyContexts = new ConcurrentDictionary(); /// /// 每个类库下面至少需要有“Serein.Library.dll”类库依赖 /// /// /// private bool CheckBaseLibrary(string libraryfilePath, out string baseLibraryPath) { var dir = Path.GetDirectoryName(libraryfilePath); // 获取目录路径 var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary); if (!Path.Exists(sereinFlowBaseLibraryPath)) { baseLibraryPath = string.Empty; return false; } baseLibraryPath = sereinFlowBaseLibraryPath; return true; } /// /// 加载基础依赖 /// public FlowLibraryInfo LoadBaseLibrary() { Assembly baseAssmbly = typeof(FlowBaseLibrary).Assembly; var flowLibrary = new FlowLibraryCache(baseAssmbly); flowLibrary.LoadFlowMethod(); var assemblyName = baseAssmbly.GetName().Name; if (string.IsNullOrEmpty(assemblyName)) { throw new Exception($"程序集\"{baseAssmbly}\"返回 Name 为 null"); } _flowLibraryCaches.TryAdd(assemblyName, flowLibrary); return flowLibrary.ToInfo(); } /// /// 加载流程依赖 /// /// /// public FlowLibraryInfo? LoadFlowLibrary(string libraryfilePath) { if (!CheckBaseLibrary(libraryfilePath, out var baseLibraryPath)) { throw new Exception($"从文件加载DLL失败,目标文件夹不存在{SereinBaseLibrary}文件"); } FlowLibraryAssemblyContext flowAlc = new FlowLibraryAssemblyContext(baseLibraryPath, Path.GetFileName(libraryfilePath)); var flowAssembly = flowAlc.LoadFromAssemblyPath(libraryfilePath); if(flowAssembly is null) { throw new Exception($"从文件加载DLL失败,FlowLibraryAssemblyContext 加载的程序集为 null \"{libraryfilePath}\""); } var flowLibrary = new FlowLibraryCache(flowAssembly); var isSuccess = flowLibrary.LoadFlowMethod(); if (!isSuccess) { flowAlc?.Unload(); // 卸载程序集 GC.Collect(); // 强制触发GC确保卸载成功 GC.WaitForPendingFinalizers(); return null; } else { var assemblyName = flowAssembly.GetName().Name; if (string.IsNullOrEmpty(assemblyName)) { flowLibrary.Unload(); flowAlc?.Unload(); // 卸载程序集 GC.Collect(); // 强制触发GC确保卸载成功 GC.WaitForPendingFinalizers(); return null; throw new Exception($"程序集\"{flowAssembly}\"返回 Name 为 null"); } _flowLibraryCaches.TryAdd(assemblyName, flowLibrary); return flowLibrary.ToInfo(); } } /// /// 卸载类库 /// /// /// public bool UnloadLibrary(string assemblyName) { if (_flowLibraryCaches.Remove(assemblyName, out var flowLibrary)) { try { flowLibrary.Unload(); // 尝试卸载 flowLibrary = null; return true; } catch (Exception ex) { SereinEnv.WriteLine(InfoType.ERROR, $"尝试卸载程序集[{assemblyName}]发生错误:{ex.Message}"); return false; } } else { return false; } } #region 获取流程依赖的相关方法 /// /// 获取方法描述 /// /// 程序集名称 /// 方法名称 /// 返回的方法描述 /// 是否获取成功 public bool TryGetMethodInfo(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodInfo methodInfo) { if (string.IsNullOrEmpty(assemblyName) || string.IsNullOrEmpty(methodName)) { methodInfo = null; return false; } if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary) && flowLibrary.MethodInfos.TryGetValue(methodName, out methodInfo)) { return true; } else { methodInfo = null; return false; } } /// /// 获取方法描述 /// /// 程序集名称 /// 方法名称 /// 返回的方法描述 /// 是否获取成功 public bool TryGetMethodDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodDetails md) { if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary) && flowLibrary.MethodDetailss.TryGetValue(methodName, out md)) { return true; } else { md = null; return false; } } /// /// 获取方法调用的委托 /// /// 程序集名称 /// 方法名称 /// 返回的委托调用封装类 /// 是否获取成功 public bool TryGetDelegateDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out DelegateDetails dd) { if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary) && flowLibrary.DelegateDetailss.TryGetValue(methodName, out dd)) { return true; } else { dd = null; return false; } } /// /// 获取(初始化/加载时/退出后)相应的节点方法 /// /// /// public List GetMdsOnFlowStart(NodeType nodeType) { List mds = []; foreach (var library in _flowLibraryCaches.Values) { var t_mds = library.MethodDetailss.Values.Where(it => it.MethodDynamicType == nodeType).ToList(); mds.AddRange(t_mds); } return mds; } /// /// 获取流程启动时在不同时间点需要自动实例化的类型 /// /// public Dictionary> GetaAutoRegisterType() { Dictionary> rsTypes = new Dictionary>(); foreach (var library in _flowLibraryCaches.Values) { foreach (var kv in library.RegisterTypes) { var @class = kv.Key; var type = kv.Value; if (!rsTypes.TryGetValue(@class, out var tmpTypes)) { tmpTypes = new List(); rsTypes.Add(@class, tmpTypes); } tmpTypes.AddRange(type); } } return rsTypes; } /// /// 获取某个程序集下的所有方法信息,用于保存项目时调用 /// /// public List GetLibraryMdsOfAssmbly(string assemblyName) { if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary)) { return flowLibrary.MethodDetailss.Values.ToList(); } return []; } /// /// 获取流程方法信息,用于保存项目时调用 /// /// public List GetAllLibraryMds() { List mds = new List(); foreach (FlowLibraryCache library in _flowLibraryCaches.Values) { var tmp = new FlowLibraryInfo { AssemblyName = library.FullName, MethodInfos = library.MethodDetailss.Values.Select(md => md.ToInfo()).ToList() }; mds.Add(tmp); } return mds; } /// /// 序列化当前项目的依赖信息、节点信息,用于远程登录的场景,需要将依赖信息从本地(受控端)发送到远程(主控端) /// /// public List GetAllLibraryInfo() { return _flowLibraryCaches.Values.Select(library => library.ToInfo()).ToList(); } #endregion #region 功能性方法 /// /// 基础依赖 /// public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Library)}.dll"; #endregion } }