diff --git a/Library/Enums/NodeType.cs b/Library/Enums/NodeType.cs
index 6c5af06..37f7fbc 100644
--- a/Library/Enums/NodeType.cs
+++ b/Library/Enums/NodeType.cs
@@ -124,6 +124,11 @@ namespace Serein.Library
///
[Description("base")]
Script,
+ ///
+ /// C#脚本节点
+ ///
+ [Description("base")]
+ NetScript,
}
}
diff --git a/Library/FlowNode/NodeModelBaseFunc.cs b/Library/FlowNode/NodeModelBaseFunc.cs
index d37ff55..bd2a1d8 100644
--- a/Library/FlowNode/NodeModelBaseFunc.cs
+++ b/Library/FlowNode/NodeModelBaseFunc.cs
@@ -65,17 +65,21 @@ namespace Serein.Library
}
this.DebugSetting.NodeModel = null;
this.DebugSetting = null;
- foreach (var pd in this.MethodDetails.ParameterDetailss)
+ if(this.MethodDetails.ParameterDetailss != null)
{
- pd.DataValue = null;
- pd.Items = null;
- pd.NodeModel = null;
- pd.ExplicitType = null;
- pd.DataType = null;
- pd.Name = null;
- pd.ArgDataSourceNodeGuid = null;
- pd.InputType = ParameterValueInputType.Input;
+ foreach (var pd in this.MethodDetails.ParameterDetailss)
+ {
+ pd.DataValue = null;
+ pd.Items = null;
+ pd.NodeModel = null;
+ pd.ExplicitType = null;
+ pd.DataType = null;
+ pd.Name = null;
+ pd.ArgDataSourceNodeGuid = null;
+ pd.InputType = ParameterValueInputType.Input;
+ }
}
+
this.MethodDetails.ParameterDetailss = null;
this.MethodDetails.ActingInstance = null;
this.MethodDetails.NodeModel = null;
diff --git a/Library/Utils/SereinEnv.cs b/Library/Utils/SereinEnv.cs
index f551f42..8ecc03c 100644
--- a/Library/Utils/SereinEnv.cs
+++ b/Library/Utils/SereinEnv.cs
@@ -9,7 +9,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
-namespace Serein.Library.Utils
+namespace Serein.Library
{
public static class SereinEnv
{
diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs
index abfd5d6..35c6de0 100644
--- a/NodeFlow/Env/FlowEnvironment.cs
+++ b/NodeFlow/Env/FlowEnvironment.cs
@@ -5,6 +5,7 @@ using Serein.Library.Utils.SereinExpression;
using Serein.NodeFlow.Model;
using Serein.NodeFlow.Tool;
using System.Reactive;
+using System.Reflection;
using System.Text;
namespace Serein.NodeFlow.Env
@@ -52,6 +53,7 @@ namespace Serein.NodeFlow.Env
NodeMVVMManagement.RegisterModel(NodeControlType.ConditionRegion, typeof(CompositeConditionNode)); // 条件区域
NodeMVVMManagement.RegisterModel(NodeControlType.GlobalData, typeof(SingleGlobalDataNode)); // 全局数据节点
NodeMVVMManagement.RegisterModel(NodeControlType.Script, typeof(SingleScriptNode)); // 脚本节点
+ NodeMVVMManagement.RegisterModel(NodeControlType.NetScript, typeof(SingleNetScriptNode)); // 脚本节点
#endregion
#region 注册基本服务类
@@ -647,9 +649,30 @@ namespace Serein.NodeFlow.Env
{
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件:{ex}");
}
+ }
+
+ ///
+ /// 加载本地程序集
+ ///
+ ///
+ public void LoadLibrary(Assembly assembly)
+ {
+ try
+ {
+ (var libraryInfo, var mdInfos) = FlowLibraryManagement.LoadLibraryOfPath(assembly);
+ if (mdInfos.Count > 0)
+ {
+ UIContextOperation?.Invoke(() => OnDllLoad?.Invoke(new LoadDllEventArgs(libraryInfo, mdInfos))); // 通知UI创建dll面板显示
+ }
+ }
+ catch (Exception ex)
+ {
+ SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件:{ex}");
+ }
}
+
///
/// 移除DLL
///
diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs
index 9e06786..4f8f127 100644
--- a/NodeFlow/FlowStarter.cs
+++ b/NodeFlow/FlowStarter.cs
@@ -76,7 +76,7 @@ namespace Serein.NodeFlow
flipflopNodes = nodes.Where(it => it.MethodDetails?.MethodDynamicType == NodeType.Flipflop && it.IsStart == false)
.Select(it => (SingleFlipflopNode)it)
- .Where(node => node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode())
+ .Where(node => node.DebugSetting.IsEnable && node is SingleFlipflopNode flipflopNode && flipflopNode.NotExitPreviousNode())
.ToList();// 获取需要再运行开始之前启动的触发器节点
runNodeMd = nodes.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息
diff --git a/NodeFlow/Model/SingleGlobalDataNode.cs b/NodeFlow/Model/SingleGlobalDataNode.cs
index 6860f90..56db45f 100644
--- a/NodeFlow/Model/SingleGlobalDataNode.cs
+++ b/NodeFlow/Model/SingleGlobalDataNode.cs
@@ -14,7 +14,7 @@ namespace Serein.NodeFlow.Model
{
- ///
+ ///
/// Expression Operation - 表达式操作
///
[NodeProperty(ValuePath = NodeValuePath.Node)]
@@ -51,7 +51,11 @@ namespace Serein.NodeFlow.Model
///
private NodeModelBase? DataNode;
-
+ ///
+ /// 有节点被放置
+ ///
+ ///
+ ///
public bool PlaceNode(NodeModelBase nodeModel)
{
if(DataNode is null)
diff --git a/NodeFlow/Model/SingleNetScriptNode.cs b/NodeFlow/Model/SingleNetScriptNode.cs
new file mode 100644
index 0000000..ad99eac
--- /dev/null
+++ b/NodeFlow/Model/SingleNetScriptNode.cs
@@ -0,0 +1,122 @@
+using Serein.Library;
+using Serein.Library.Api;
+using System;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.NodeFlow.Model
+{
+
+ [NodeProperty(ValuePath = NodeValuePath.Node)]
+ public partial class SingleNetScriptNode : NodeModelBase
+ {
+ ///
+ /// 脚本代码
+ ///
+ [PropertyInfo(IsNotification = true)]
+ private string _script;
+
+ ///
+ /// 功能提示
+ ///
+ [PropertyInfo(IsNotification = true)]
+ private string _tips = "写一下提示吧";
+
+ ///
+ /// 依赖路径
+ ///
+ [PropertyInfo(IsNotification = true)]
+ private List _libraryFilePaths;
+
+ }
+
+ public partial class SingleNetScriptNode
+ {
+ ///
+ /// 表达式节点是基础节点
+ ///
+ public override bool IsBase => true;
+
+ public SingleNetScriptNode(IFlowEnvironment environment) : base(environment)
+ {
+ this.Env = environment;
+ }
+
+
+
+
+
+ public override void OnCreating()
+ {
+ //MethodInfo? method = this.GetType().GetMethod(nameof(GetFlowApi));
+ //if (method != null)
+ //{
+ // ScriptInterpreter.AddFunction(nameof(GetFlowApi), method, () => this); // 挂载获取流程接口
+ //}
+
+ //var md = MethodDetails;
+ //var pd = md.ParameterDetailss ??= new ParameterDetails[1];
+ //md.ParamsArgIndex = 0;
+ //pd[0] = new ParameterDetails
+ //{
+ // Index = 0,
+ // Name = "object",
+ // IsExplicitData = true,
+ // DataValue = string.Empty,
+ // DataType = typeof(object),
+ // ExplicitType = typeof(object),
+ // ArgDataSourceNodeGuid = string.Empty,
+ // ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData,
+ // NodeModel = this,
+ // InputType = ParameterValueInputType.Input,
+ // Items = null,
+ // IsParams = true,
+ // Description = "脚本节点入参"
+
+ //};
+
+ }
+
+ ///
+ /// 导出脚本代码
+ ///
+ ///
+ ///
+ public override NodeInfo SaveCustomData(NodeInfo nodeInfo)
+ {
+ dynamic data = new ExpandoObject();
+ data.Script = this.Script ?? "";
+ nodeInfo.CustomData = data;
+ return nodeInfo;
+ }
+
+ ///
+ /// 加载自定义数据
+ ///
+ ///
+ public override void LoadCustomData(NodeInfo nodeInfo)
+ {
+ this.Script = nodeInfo.CustomData?.Script ?? "";
+
+ // 更新变量名
+ //for (int i = 0; i < Math.Min(this.MethodDetails.ParameterDetailss.Length, nodeInfo.ParameterData.Length); i++)
+ //{
+ // this.MethodDetails.ParameterDetailss[i].Name = nodeInfo.ParameterData[i].ArgName;
+ //}
+
+
+ }
+
+
+
+
+
+
+
+
+ }
+}
diff --git a/NodeFlow/Model/SingleScriptNode.cs b/NodeFlow/Model/SingleScriptNode.cs
index 239a6d6..fda4f1f 100644
--- a/NodeFlow/Model/SingleScriptNode.cs
+++ b/NodeFlow/Model/SingleScriptNode.cs
@@ -28,13 +28,11 @@ namespace Serein.NodeFlow.Model
///
public partial class SingleScriptNode : NodeModelBase
{
-
///
/// 脚本节点是基础节点
///
public override bool IsBase => true;
-
private IScriptFlowApi ScriptFlowApi { get; }
private ASTNode mainNode;
diff --git a/Library/Utils/DynamicCompiler.cs b/NodeFlow/Tool/DynamicCompiler.cs
similarity index 75%
rename from Library/Utils/DynamicCompiler.cs
rename to NodeFlow/Tool/DynamicCompiler.cs
index c835194..7b563e9 100644
--- a/Library/Utils/DynamicCompiler.cs
+++ b/NodeFlow/Tool/DynamicCompiler.cs
@@ -9,7 +9,7 @@ using System.Reflection;
using System.Text;
using System.Threading.Tasks;
-namespace Serein.Library.Utils
+namespace Serein.NodeFlow.Tool
{
///
/// 动态编译
@@ -22,7 +22,7 @@ namespace Serein.Library.Utils
{
// 默认添加当前 AppDomain 加载的所有程序集
var defaultReferences = AppDomain.CurrentDomain.GetAssemblies()
- .Where(a => !string.IsNullOrEmpty(a.Location)) // a.IsDynamic 动态程序集
+ .Where(a => !string.IsNullOrEmpty(a.Location)) // a.IsDynamic 动态程序集
.Select(a => MetadataReference.CreateFromFile(a.Location));
@@ -64,17 +64,28 @@ namespace Serein.Library.Utils
public Assembly Compile(string code, string assemblyName = null)
{
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
- if(assemblyName is null)
+ if (assemblyName is null)
{
assemblyName = Path.GetRandomFileName(); // 生成随机程序集名称
}
+ var temp_dir = Path.Combine(Directory.GetCurrentDirectory(), "temp");
+ if (!Directory.Exists(temp_dir))
+ {
+ Directory.CreateDirectory(temp_dir);
+ }
+ var savePath = Path.Combine(temp_dir, $"{assemblyName}.dll");
+
+ var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
+
+
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
new[] { syntaxTree },
_references,
- new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
+ options
+
);
using (var ms = new MemoryStream())
@@ -90,11 +101,27 @@ namespace Serein.Library.Utils
}
return null;
}
-
ms.Seek(0, SeekOrigin.Begin);
- return Assembly.Load(ms.ToArray());
+ var assembly = Assembly.Load(ms.ToArray());
+ var t1 = assembly.Location;
+ var t = assembly.GetType().Assembly.Location;
+
+
+
+ // 保存
+
+ compilation.Emit(savePath);
+ return assembly;
}
-
+
}
+
+ public void Save()
+ {
+
+ }
+
+
+
}
}
diff --git a/NodeFlow/Tool/FlowLibrary.cs b/NodeFlow/Tool/FlowLibrary.cs
index 35c4bb9..56923af 100644
--- a/NodeFlow/Tool/FlowLibrary.cs
+++ b/NodeFlow/Tool/FlowLibrary.cs
@@ -26,19 +26,33 @@ namespace Serein.NodeFlow
///
public class FlowLibrary
{
- private readonly Assembly assembly;
- private readonly Action actionOfUnloadAssmbly;
+ private readonly Assembly _assembly;
- public FlowLibrary(Assembly assembly,
- Action actionOfUnloadAssmbly)
+
+
+ //private readonly Action actionOfUnloadAssmbly;
+ /*, Action actionOfUnloadAssmbly*/
+ //this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
+
+ public FlowLibrary(Assembly assembly)
{
- this.assembly = assembly;
- this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
+ this._assembly = assembly;
+ this.FullName = Path.GetFileName(_assembly.Location);
+
+ this.FilePath = _assembly.Location;
}
- public string FullName => assembly.GetName().FullName;
+ public FlowLibrary(Assembly assembly,
+ string filePath)
+ {
+ this._assembly = assembly;
+ this.FullName = Path.GetFileName(filePath); ;
+ this.FilePath = filePath;
+ }
- public string Version => assembly.GetName().Version.ToString();
+ public string FullName { get; private set; }
+
+ public string FilePath { get; private set; }
///
/// 加载程序集时创建的方法描述
@@ -68,7 +82,7 @@ namespace Serein.NodeFlow
DelegateDetailss.Clear();
RegisterTypes.Clear();
MethodDetailss.Clear();
- actionOfUnloadAssmbly?.Invoke();
+ //actionOfUnloadAssmbly?.Invoke();
}
@@ -78,11 +92,12 @@ namespace Serein.NodeFlow
///
public NodeLibraryInfo ToInfo()
{
+ var assemblyName = _assembly.GetName().Name;
return new NodeLibraryInfo
{
- AssemblyName = assembly.GetName().Name,
- FileName = Path.GetFileName(assembly.Location),
- FilePath = assembly.Location,
+ AssemblyName = assemblyName,
+ FileName = this.FullName,
+ FilePath = this.FilePath,
};
@@ -94,8 +109,9 @@ namespace Serein.NodeFlow
///
/// 程序集本身
///
- public bool LoadAssembly(Assembly assembly)
+ public bool LoadAssembly()
{
+ Assembly assembly = this._assembly;
#region 检查入参
// 加载DLL,创建 MethodDetails、实例作用对象、委托方法
diff --git a/NodeFlow/Tool/FlowLibraryManagement.cs b/NodeFlow/Tool/FlowLibraryManagement.cs
index ab3cc66..e06f953 100644
--- a/NodeFlow/Tool/FlowLibraryManagement.cs
+++ b/NodeFlow/Tool/FlowLibraryManagement.cs
@@ -39,7 +39,36 @@ namespace Serein.NodeFlow.Tool
///
public (NodeLibraryInfo, List) LoadLibraryOfPath(string libraryfilePath)
{
- return LoadDllNodeInfo(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 reulst = LoadDllNodeInfo(assembly);
+ if(reulst.Item1 is null || reulst.Item2.Count == 0)
+ {
+ flowAlc?.Unload(); // 卸载程序集
+ flowAlc = null;
+ GC.Collect(); // 强制触发GC确保卸载成功
+ GC.WaitForPendingFinalizers();
+ throw new Exception("从文件加载DLL失败:"+ libraryfilePath);
+ }
+ return reulst;
+ }
+
+ ///
+ /// 加载类库
+ ///
+ ///
+ ///
+ public (NodeLibraryInfo, List) LoadLibraryOfPath(Assembly assembly)
+ {
+ return LoadDllNodeInfo(assembly);
}
///
@@ -206,84 +235,44 @@ namespace Serein.NodeFlow.Tool
///
public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Serein.Library)}.dll";
- private (NodeLibraryInfo, List) LoadDllNodeInfo(string dllFilePath)
+ private (NodeLibraryInfo, List) LoadDllNodeInfo(Assembly assembly)
{
- var fileName = Path.GetFileName(dllFilePath); // 获取文件名
- if (SereinBaseLibrary.Equals(fileName))
+
+ if (assembly.FullName?.ToString().Equals(typeof(IFlowEnvironment).Assembly.FullName?.ToString()) == true)
{
- return LoadAssembly(typeof(IFlowEnvironment).Assembly, () => {
- //SereinEnv.PrintInfo(InfoType.WRAN, "基础模块不能卸载");
- });
+ // 加载基础依赖
+ return LoadAssembly(typeof(IFlowEnvironment).Assembly);
}
else
{
- var dir = Path.GetDirectoryName(dllFilePath); // 获取目录路径
- var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);
- // 每个类库下面至少需要有“Serein.Library.dll”类库依赖
-
- //AssemblyLoader assemblyLoader = new AssemblyLoader(dllFilePath);
-
-
- var flowAlc = new FlowLibraryAssemblyContext(sereinFlowBaseLibraryPath, fileName);
- Action actionUnload = () =>
+ try
{
- flowAlc?.Unload(); // 卸载程序集
- flowAlc = null;
- GC.Collect(); // 强制触发GC确保卸载成功
- GC.WaitForPendingFinalizers();
- };
- var assembly = flowAlc.LoadFromAssemblyPath(dllFilePath); // 加载指定路径的程序集
- var assembly_result = LoadAssembly(assembly, actionUnload);
- return assembly_result;
+ var assembly_result = LoadAssembly(assembly);
+ return assembly_result;
+ }
+ catch (Exception)
+ {
+ return (null,[]);
+ }
+
}
- /* 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); // 加载指定路径的程序集
- 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);
- (NodeLibraryInfo, List) result = (flowLibrary.ToInfo(),
- flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList());
- return result;
- }
- else
- {
- throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
- }*/
}
- private (NodeLibraryInfo, List) LoadAssembly(Assembly assembly,Action actionUnload)
+ private (NodeLibraryInfo, List) LoadAssembly(Assembly assembly)
{
if (_myFlowLibrarys.ContainsKey(assembly.GetName().Name))
{
- actionUnload.Invoke();
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
}
- FlowLibrary flowLibrary = new FlowLibrary(assembly, actionUnload);
- var loadResult = flowLibrary.LoadAssembly(assembly); // 加载程序集
+ FlowLibrary flowLibrary = new FlowLibrary(assembly);
+ var loadResult = flowLibrary.LoadAssembly(); // 加载程序集
if (loadResult)
{
var assemblyName = assembly.GetName().Name;
if (string.IsNullOrEmpty(assemblyName))
{
- actionUnload.Invoke();
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败,没有程序集名称");
}
_myFlowLibrarys.TryAdd(assemblyName, flowLibrary);
@@ -296,7 +285,6 @@ namespace Serein.NodeFlow.Tool
}
else
{
- actionUnload.Invoke();
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
}
}
diff --git a/NodeFlow/Tool/NodeMethodDetailsHelper.cs b/NodeFlow/Tool/NodeMethodDetailsHelper.cs
index 63b0dbd..fffa778 100644
--- a/NodeFlow/Tool/NodeMethodDetailsHelper.cs
+++ b/NodeFlow/Tool/NodeMethodDetailsHelper.cs
@@ -19,7 +19,7 @@ public static class NodeMethodDetailsHelper
///
public static IEnumerable GetMethodsToProcess(Type type)
{
- return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
+ return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
.Where(m => m.GetCustomAttribute()?.Scan == true);
}
diff --git a/Workbench/App.xaml.cs b/Workbench/App.xaml.cs
index bcc7959..deeb37b 100644
--- a/Workbench/App.xaml.cs
+++ b/Workbench/App.xaml.cs
@@ -24,6 +24,7 @@ namespace Serein.Workbench
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\net8.0\PLCproject.dnf";
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\banyunqi\project.dnf";
filePath = @"F:\临时\project\project.dnf";
+ filePath = @"F:\临时\flow\qrcode\project.dnf";
//filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\test.dnf";
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
App.FlowProjectData = JsonConvert.DeserializeObject(content);
diff --git a/Workbench/MainWindow.xaml b/Workbench/MainWindow.xaml
index 87cef37..399f48c 100644
--- a/Workbench/MainWindow.xaml
+++ b/Workbench/MainWindow.xaml
@@ -46,11 +46,16 @@