mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
在Serein.Library添加了基础功能模块,暂时实现了键值对/数组数据的创建(可配合JSON库进行序列化)
This commit is contained in:
@@ -13,36 +13,35 @@ namespace Serein.NodeFlow
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 加载在流程中的程序集依赖
|
||||
/// </summary>
|
||||
public class FlowLibrary
|
||||
{
|
||||
private readonly Assembly assembly;
|
||||
private readonly Action actionOfUnloadAssmbly;
|
||||
private string _assemblyFilePath;
|
||||
|
||||
public FlowLibrary(string assemblyFilePath,
|
||||
Assembly assembly,
|
||||
public FlowLibrary(Assembly assembly,
|
||||
Action actionOfUnloadAssmbly)
|
||||
{
|
||||
this._assemblyFilePath = assemblyFilePath;
|
||||
this.assembly = assembly;
|
||||
this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public string FullName => assembly.GetName().FullName;
|
||||
|
||||
public string Version => assembly.GetName().Version.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// 加载程序集时创建的方法描述
|
||||
/// Key : 方法名称
|
||||
/// Value :方法详情
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, MethodDetails> MethodDetailss { get; } = new ConcurrentDictionary<string, MethodDetails>();
|
||||
|
||||
/// <summary>
|
||||
/// 管理通过Emit动态构建的委托
|
||||
/// Key :方法名称
|
||||
/// Value :方法详情
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, DelegateDetails> DelegateDetailss { get; } = new ConcurrentDictionary<string, DelegateDetails>();
|
||||
|
||||
@@ -57,56 +56,24 @@ namespace Serein.NodeFlow
|
||||
/// </summary>
|
||||
public void Upload()
|
||||
{
|
||||
DelegateDetailss.Clear();
|
||||
RegisterTypes.Clear();
|
||||
MethodDetailss.Clear();
|
||||
actionOfUnloadAssmbly?.Invoke();
|
||||
|
||||
}
|
||||
|
||||
public NodeLibraryInfo ToInfo()
|
||||
{
|
||||
return new NodeLibraryInfo
|
||||
{
|
||||
AssemblyName = FullName,
|
||||
FileName = Path.GetFileName(_assemblyFilePath),
|
||||
FilePath = _assemblyFilePath,
|
||||
AssemblyName = assembly.GetName().Name,
|
||||
FileName = Path.GetFileName(assembly.Location),
|
||||
FilePath = assembly.Location,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//public void LoadAssmely(Assembly assembly)
|
||||
//{
|
||||
// (var registerTypes, var mdlist) = LoadAssembly2(assembly);
|
||||
// if (mdlist.Count > 0)
|
||||
// {
|
||||
// var nodeLibraryInfo = new NodeLibraryInfo
|
||||
// {
|
||||
// //Assembly = assembly,
|
||||
// AssemblyName = assembly.FullName,
|
||||
// FileName = Path.GetFileName(_assemblyFilePath),
|
||||
// FilePath = _assemblyFilePath,
|
||||
// };
|
||||
|
||||
// //LibraryInfos.TryAdd(nodeLibraryInfo.AssemblyName, nodeLibraryInfo);
|
||||
|
||||
// MethodDetailss.TryAdd(nodeLibraryInfo.AssemblyName, mdlist);
|
||||
|
||||
// foreach (var md in mdlist)
|
||||
// {
|
||||
// MethodDetailss.TryAdd(md.MethodName, md);
|
||||
// }
|
||||
|
||||
// foreach (var kv in registerTypes)
|
||||
// {
|
||||
// if (!RegisterTypes.TryGetValue(kv.Key, out var types))
|
||||
// {
|
||||
// types = new List<Type>();
|
||||
// RegisterTypes.TryAdd(kv.Key, types);
|
||||
// }
|
||||
// types.AddRange(kv.Value);
|
||||
// }
|
||||
// var mdInfos = mdlist.Select(md => md.ToInfo()).ToList(); // 转换成方法信息
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 动态加载程序集
|
||||
/// </summary>
|
||||
@@ -158,18 +125,13 @@ namespace Serein.NodeFlow
|
||||
// (Type, string)
|
||||
// Type : 具有 DynamicFlowAttribute 标记的类型
|
||||
// string : 类型元数据 DynamicFlowAttribute 特性中的 Name 属性
|
||||
|
||||
types = types.Where(type => type.GetCustomAttribute<DynamicFlowAttribute>() is DynamicFlowAttribute dynamicFlowAttribute
|
||||
&& dynamicFlowAttribute.Scan).ToList();
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
if (type.Name.Equals("YoloFlowControl"))
|
||||
{
|
||||
//var ab = type.GetCustomAttribute<DynamicFlowAttribute>();
|
||||
//var attributes = assembly.GetCustomAttributes();
|
||||
//foreach (var attribute in attributes)
|
||||
//{
|
||||
// Console.WriteLine(attribute.GetType().Name);
|
||||
//}
|
||||
}
|
||||
if (type.GetCustomAttribute<DynamicFlowAttribute>() is DynamicFlowAttribute dynamicFlowAttribute && dynamicFlowAttribute.Scan == true)
|
||||
if (type.GetCustomAttribute<DynamicFlowAttribute>() is DynamicFlowAttribute dynamicFlowAttribute)
|
||||
{
|
||||
scanTypes.Add((type, dynamicFlowAttribute.Name));
|
||||
}
|
||||
|
||||
@@ -31,25 +31,34 @@ namespace Serein.NodeFlow.Tool
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, FlowLibrary> _myFlowLibrarys = new ConcurrentDictionary<string, FlowLibrary>();
|
||||
|
||||
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibrary(string libraryfilePath)
|
||||
/// <summary>
|
||||
/// 加载类库
|
||||
/// </summary>
|
||||
/// <param name="libraryfilePath"></param>
|
||||
/// <returns></returns>
|
||||
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(string libraryfilePath)
|
||||
{
|
||||
|
||||
return LoadDllNodeInfo(libraryfilePath);
|
||||
}
|
||||
|
||||
public bool UnloadLibrary(string libraryName)
|
||||
/// <summary>
|
||||
/// 卸载类库
|
||||
/// </summary>
|
||||
/// <param name="assemblyName"></param>
|
||||
/// <returns></returns>
|
||||
public bool UnloadLibrary(string assemblyName)
|
||||
{
|
||||
libraryName = libraryName.Split(',')[0];
|
||||
if (_myFlowLibrarys.Remove(libraryName, out var flowLibrary))
|
||||
if (_myFlowLibrarys.Remove(assemblyName, out var flowLibrary))
|
||||
{
|
||||
try
|
||||
{
|
||||
flowLibrary.Upload();
|
||||
flowLibrary.Upload(); // 尝试卸载
|
||||
flowLibrary = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"尝试卸载程序集[{libraryName}]发生错误:{ex}");
|
||||
Console.WriteLine($"尝试卸载程序集[{assemblyName}]发生错误:{ex}");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -144,6 +153,20 @@ namespace Serein.NodeFlow.Tool
|
||||
return rsTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取某个程序集下的所有方法信息,用于保存项目时调用
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<MethodDetails> GetLibraryMdsOfAssmbly(string assemblyName)
|
||||
{
|
||||
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary))
|
||||
{
|
||||
return flowLibrary.MethodDetailss.Values.ToList();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有方法信息,用于保存项目时调用
|
||||
@@ -165,9 +188,6 @@ namespace Serein.NodeFlow.Tool
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 序列化当前项目的依赖信息、节点信息,用于远程登录的场景,需要将依赖信息从本地(受控端)发送到远程(主控端)
|
||||
/// </summary>
|
||||
@@ -180,18 +200,38 @@ namespace Serein.NodeFlow.Tool
|
||||
|
||||
#region 功能性方法
|
||||
|
||||
/// <summary>
|
||||
/// 从文件路径中加载程序集,返回相应的信息
|
||||
/// </summary>
|
||||
/// <param name="dllFilePath"></param>
|
||||
/// <returns></returns>
|
||||
private readonly string SereinLibraryDll = $"{nameof(Serein)}.{nameof(Serein.Library)}.dll";
|
||||
|
||||
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadDllNodeInfo(string dllFilePath)
|
||||
{
|
||||
|
||||
#if true
|
||||
var fileName = Path.GetFileName(dllFilePath); // 获取文件名
|
||||
var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径
|
||||
var sereinFlowLibraryPath = Path.Combine(dir, $"{nameof(Serein)}.{nameof(Serein.Library)}.dll");
|
||||
|
||||
if (SereinLibraryDll.Equals(fileName))
|
||||
{
|
||||
|
||||
return LoadAssembly(typeof(IFlowEnvironment).Assembly, () => {
|
||||
//Console.WriteLine("基础模块不能卸载");
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径
|
||||
var sereinFlowLibraryPath = Path.Combine(dir, SereinLibraryDll);
|
||||
// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
|
||||
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowLibraryPath, fileName);
|
||||
Action actionUnload = () =>
|
||||
{
|
||||
flowAlc?.Unload(); // 卸载程序集
|
||||
flowAlc = null;
|
||||
GC.Collect(); // 强制触发GC确保卸载成功
|
||||
GC.WaitForPendingFinalizers();
|
||||
};
|
||||
var assembly = flowAlc.LoadFromAssemblyPath(dllFilePath); // 加载指定路径的程序集
|
||||
return LoadAssembly(assembly, actionUnload);
|
||||
}
|
||||
|
||||
/* var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径
|
||||
var sereinFlowLibraryPath = Path.Combine(dir, SereinLibraryDll);
|
||||
// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
|
||||
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowLibraryPath, fileName);
|
||||
Action actionUnload = () =>
|
||||
@@ -207,8 +247,29 @@ namespace Serein.NodeFlow.Tool
|
||||
actionUnload.Invoke();
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
|
||||
}
|
||||
FlowLibrary flowLibrary = new FlowLibrary(assembly, actionUnload);
|
||||
if (flowLibrary.LoadAssembly(assembly))
|
||||
{
|
||||
_myFlowLibrarys.TryAdd(assembly.GetName().Name, flowLibrary);
|
||||
(NodeLibraryInfo, List<MethodDetailsInfo>) result = (flowLibrary.ToInfo(),
|
||||
flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList());
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
|
||||
}*/
|
||||
}
|
||||
|
||||
FlowLibrary flowLibrary = new FlowLibrary(dllFilePath, assembly, actionUnload);
|
||||
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadAssembly(Assembly assembly,Action actionUnload)
|
||||
{
|
||||
if (_myFlowLibrarys.ContainsKey(assembly.GetName().Name))
|
||||
{
|
||||
actionUnload.Invoke();
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
|
||||
}
|
||||
|
||||
FlowLibrary flowLibrary = new FlowLibrary(assembly, actionUnload);
|
||||
if (flowLibrary.LoadAssembly(assembly))
|
||||
{
|
||||
_myFlowLibrarys.TryAdd(assembly.GetName().Name, flowLibrary);
|
||||
@@ -220,29 +281,6 @@ namespace Serein.NodeFlow.Tool
|
||||
{
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
|
||||
}
|
||||
|
||||
#else
|
||||
var fileName = Path.GetFileName(dllFilePath); // 获取文件名
|
||||
Assembly assembly = Assembly.LoadFrom(dllFilePath); // 加载程序集
|
||||
FlowLibrary flowLibrary = new FlowLibrary(dllFilePath, assembly, () =>
|
||||
{
|
||||
Console.WriteLine("暂未实现卸载程序集");
|
||||
//flowAlc.Unload(); // 卸载程序集
|
||||
//flowAlc = null;
|
||||
//GC.Collect(); // 强制触发GC确保卸载成功
|
||||
//GC.WaitForPendingFinalizers();
|
||||
});
|
||||
|
||||
_myFlowLibrarys.TryAdd(assembly.GetName().Name, flowLibrary);
|
||||
|
||||
(NodeLibraryInfo, List<MethodDetailsInfo>) result = (flowLibrary.ToInfo(),
|
||||
flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList());
|
||||
return result;
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -281,6 +319,7 @@ namespace Serein.NodeFlow.Tool
|
||||
return Default.Assemblies.FirstOrDefault(x => x.FullName == assemblyName.FullName);
|
||||
}
|
||||
|
||||
// return null;
|
||||
|
||||
// 构建依赖项的路径
|
||||
//string assemblyPath = Path.Combine(AppContext.BaseDirectory, assemblyName.Name + ".dll");
|
||||
|
||||
@@ -60,8 +60,7 @@ public static class NodeMethodDetailsHelper
|
||||
// method.GetParameters(),// 方法参数
|
||||
// method.ReturnType);// 返回值
|
||||
|
||||
//// 通过表达式树生成委托
|
||||
var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var methodDelegate);// 返回值
|
||||
|
||||
|
||||
Type? returnType;
|
||||
bool isTask = IsGenericTask(methodInfo.ReturnType, out var taskResult);
|
||||
@@ -137,7 +136,11 @@ public static class NodeMethodDetailsHelper
|
||||
// 如果存在可变参数,取最后一个元素的下标,否则为-1;
|
||||
ParamsArgIndex = hasParamsArg ? explicitDataOfParameters.Length - 1 : -1,
|
||||
};
|
||||
var dd = new DelegateDetails(emitMethodType, methodDelegate) ;
|
||||
|
||||
//var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var methodDelegate);// 返回值
|
||||
|
||||
|
||||
var dd = new DelegateDetails(methodInfo) ; // 构造委托
|
||||
|
||||
methodDetails = md;
|
||||
delegateDetails = dd;
|
||||
|
||||
Reference in New Issue
Block a user