using Serein.Library; using Serein.Library.Api; using Serein.Library.FlowNode; using Serein.Library.Utils; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.Loader; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; namespace Serein.NodeFlow.Tool { /// /// 管理加载在运行环境中的外部程序集 /// public class FlowLibraryManagement { public FlowLibraryManagement(IFlowEnvironment flowEnvironment) { this.flowEnvironment = flowEnvironment; } private readonly IFlowEnvironment flowEnvironment; /// /// 缓存所有加载了的程序集 /// private readonly ConcurrentDictionary _myFlowLibrarys = new ConcurrentDictionary(); /// /// 加载类库 /// /// /// public (NodeLibraryInfo, List) LoadLibraryOfPath(string libraryfilePath) { var dir = Path.GetDirectoryName(libraryfilePath); // 获取目录路径 var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);// 每个类库下面至少需要有“Serein.Library.dll”类库依赖 if (!Path.Exists(sereinFlowBaseLibraryPath)) { throw new Exception($"从文件加载DLL失败,目标文件夹不存在{SereinBaseLibrary}文件" ); } var flowAlc = new FlowLibraryAssemblyContext(sereinFlowBaseLibraryPath, Path.GetFileName(libraryfilePath)); var assembly = flowAlc.LoadFromAssemblyPath(libraryfilePath); // 加载指定路径的程序集 var flowLibrary = new FlowLibrary(assembly); try { var reulst = LoadFlowLibrary(flowLibrary); return reulst; } catch (Exception) { flowAlc?.Unload(); // 卸载程序集 flowAlc = null; GC.Collect(); // 强制触发GC确保卸载成功 GC.WaitForPendingFinalizers(); throw; } } /// /// 加载类库 /// /// /// public (NodeLibraryInfo, List) LoadLibraryOfPath(FlowLibrary flowLibrary) { return LoadFlowLibrary(flowLibrary); } /// /// 卸载类库 /// /// /// public bool UnloadLibrary(string assemblyName) { if (_myFlowLibrarys.Remove(assemblyName, out var flowLibrary)) { try { flowLibrary.Upload(); // 尝试卸载 flowLibrary = null; return true; } catch (Exception ex) { SereinEnv.WriteLine(InfoType.ERROR, $"尝试卸载程序集[{assemblyName}]发生错误:{ex}"); return false; } } else { return false; } } /// /// 获取方法描述 /// /// 程序集名称 /// 方法名称 /// 返回的方法描述 /// 是否获取成功 public bool TryGetMethodDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodDetails md) { if (_myFlowLibrarys.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 (_myFlowLibrarys.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 _myFlowLibrarys.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 _myFlowLibrarys.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 (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary)) { return flowLibrary.MethodDetailss.Values.ToList(); } return []; } /// /// 获取所有方法信息,用于保存项目时调用 /// /// public List GetAllLibraryMds() { List mds = new List(); foreach (FlowLibrary library in _myFlowLibrarys.Values) { var tmp = new LibraryMds { AssemblyName = library.FullName, Mds = library.MethodDetailss.Values.Select(md => md.ToInfo()).ToArray() }; mds.Add(tmp); } return mds; } /// /// 序列化当前项目的依赖信息、节点信息,用于远程登录的场景,需要将依赖信息从本地(受控端)发送到远程(主控端) /// /// public List GetAllLibraryInfo() { return _myFlowLibrarys.Values.Select(library => library.ToInfo()).ToList(); } #region 功能性方法 /// /// 基础依赖 /// public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Serein.Library)}.dll"; //private (NodeLibraryInfo, List) LoadDllNodeInfo(Assembly assembly) //{ // if (assembly.FullName?.ToString().Equals(typeof(IFlowEnvironment).Assembly.FullName?.ToString()) == true) // { // // 加载基础依赖 // return LoadAssembly(typeof(IFlowEnvironment).Assembly); // } // else // { // try // { // var assembly_result = LoadAssembly(assembly); // return assembly_result; // } // catch (Exception) // { // return (null,[]); // } // } //} private (NodeLibraryInfo, List) LoadFlowLibrary(FlowLibrary flowLibrary) { var assembly = flowLibrary.Assembly; if (assembly.FullName?.ToString().Equals(typeof(IFlowEnvironment).Assembly.FullName?.ToString()) == true) { // 加载基础依赖 flowLibrary = new FlowLibrary(typeof(IFlowEnvironment).Assembly); } var assmblyName = assembly.GetName().Name; if (!string.IsNullOrEmpty(assmblyName) && _myFlowLibrarys.ContainsKey(assmblyName)) { throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!"); } var loadResult = flowLibrary.LoadAssembly(); // 加载程序集 if (loadResult) { var assemblyName = assembly.GetName().Name; if (string.IsNullOrEmpty(assemblyName)) { throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败,没有程序集名称"); } _myFlowLibrarys.TryAdd(assemblyName, flowLibrary); List mdInfos = flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList(); mdInfos.Sort((a, b) => string.Compare(a.MethodName, b.MethodName, StringComparison.OrdinalIgnoreCase)); (NodeLibraryInfo, List) result = (flowLibrary.ToInfo(), mdInfos); return result; } else { throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败"); } } #endregion } /// /// 流程依赖加载 /// public class FlowLibraryAssemblyContext : AssemblyLoadContext { private readonly AssemblyDependencyResolver _resolver; /// /// 创建新的加载上下文 /// /// 类库路径 /// public FlowLibraryAssemblyContext(string sereinFlowLibraryPath, string name) : base(name, isCollectible: true) { _resolver = new AssemblyDependencyResolver(sereinFlowLibraryPath); } protected override Assembly? Load(AssemblyName assemblyName) { string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); if (!string.IsNullOrEmpty(assemblyPath)) { var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); //var assembly = LoadFromAssemblyPath(assemblyPath); return assembly; } else { return Default.Assemblies.FirstOrDefault(x => x.FullName == assemblyName.FullName); } // return null; // 构建依赖项的路径 //string assemblyPath = Path.Combine(AppContext.BaseDirectory, assemblyName.Name + ".dll"); //if (File.Exists(assemblyPath)) //{ // return LoadFromAssemblyPath(assemblyPath); //} //assemblyPath = Path.Combine(filePath, assemblyName.Name + ".dll"); //if (File.Exists(assemblyPath)) //{ // return LoadFromAssemblyPath(assemblyPath); //} //return null; // 如果没有找到,返回 null } } //public static class PluginAssemblyContextExtensions //{ // public static Assembly FromAssemblyPath(this AssemblyLoadContext context, string path) // { // return context.LoadFromAssemblyPath(path); // } //} }