mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
重新设计了FlowLIbrary相关类;为工作台默认添加了基础依赖、默认画布。
This commit is contained in:
@@ -27,7 +27,7 @@ namespace Serein.FlowStartTool
|
||||
Console.WriteLine($"{DateTime.Now} [{infoType}] : {value}{Environment.NewLine}");
|
||||
};
|
||||
|
||||
await flowEnvironment.StartRemoteServerAsync(7525); // 启动 web socket 监听远程请求
|
||||
//await flowEnvironment.StartRemoteServerAsync(7525); // 启动 web socket 监听远程请求
|
||||
IsRuning = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -179,19 +179,14 @@ namespace Serein.Library.Api
|
||||
/// </summary>
|
||||
public class LoadDllEventArgs : FlowEventArgs
|
||||
{
|
||||
public LoadDllEventArgs(NodeLibraryInfo nodeLibraryInfo, List<MethodDetailsInfo> MethodDetailss)
|
||||
public LoadDllEventArgs(FlowLibraryInfo nodeLibraryInfo)
|
||||
{
|
||||
this.NodeLibraryInfo = nodeLibraryInfo;
|
||||
this.MethodDetailss = MethodDetailss;
|
||||
}
|
||||
/// <summary>
|
||||
/// 已加载了的程序集
|
||||
/// </summary>
|
||||
public NodeLibraryInfo NodeLibraryInfo { get;}
|
||||
/// <summary>
|
||||
/// dll文件中有效的流程方法描述
|
||||
/// </summary>
|
||||
public List<MethodDetailsInfo> MethodDetailss { get;}
|
||||
public FlowLibraryInfo NodeLibraryInfo { get;}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -791,7 +786,7 @@ namespace Serein.Library.Api
|
||||
/// <summary>
|
||||
/// 是否全局中断
|
||||
/// </summary>
|
||||
bool IsGlobalInterrupt { get; }
|
||||
bool _IsGlobalInterrupt { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>表示是否正在控制远程</para>
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
|
||||
@@ -14,18 +14,21 @@ namespace Serein.Library
|
||||
/// 基础功能
|
||||
/// </summary>
|
||||
[DynamicFlow(Name ="[基础功能]")]
|
||||
public static class SereinBaseFunction
|
||||
public static class FlowBaseLibrary
|
||||
{
|
||||
|
||||
[NodeAction(NodeType.Action, "对象透传")]
|
||||
public static object SereinTransmissionObject(object value) => value;
|
||||
public static object TransmissionObject(object value) => value;
|
||||
|
||||
[NodeAction(NodeType.Action, "键值对组装")]
|
||||
public static Dictionary<string, object> SereinKvDataCollection(string argName,
|
||||
params object[] value)
|
||||
public static Dictionary<string, object> DictSet(string argNames, params object[] value)
|
||||
{
|
||||
var names = argName.Split(';');
|
||||
var count = Math.Min(value.Length, names.Length);
|
||||
var names = argNames.Split(';');
|
||||
if(value.Length != names.Length)
|
||||
{
|
||||
throw new ArgumentException("参数名称数量与入参数量不一致");
|
||||
}
|
||||
var count = value.Length;
|
||||
var dict = new Dictionary<string, object>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@@ -35,13 +38,13 @@ namespace Serein.Library
|
||||
}
|
||||
|
||||
[NodeAction(NodeType.Action, "数组组装")]
|
||||
public static object[] SereinListDataCollection(params object[] value)
|
||||
public static object[] ArraySet(params object[] value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
[NodeAction(NodeType.Action, "输出")]
|
||||
public static object[] SereinConsole(params object[] value)
|
||||
public static object[] Console(params object[] value)
|
||||
{
|
||||
foreach (var item in value)
|
||||
{
|
||||
@@ -51,7 +54,7 @@ namespace Serein.Library
|
||||
}
|
||||
|
||||
[NodeAction(NodeType.Action, "逻辑分支")]
|
||||
public static object SereinLogicalBranch([NodeParam(IsExplicit = false)]bool @bool,
|
||||
public static object LogicalBranch([NodeParam(IsExplicit = false)]bool @bool,
|
||||
object t_value,
|
||||
object f_value)
|
||||
{
|
||||
@@ -59,7 +62,7 @@ namespace Serein.Library
|
||||
}
|
||||
|
||||
[NodeAction(NodeType.Action, "文本拼接")]
|
||||
public static string SereinTextJoin(params object[] value)
|
||||
public static string TextJoin(params object[] value)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (var item in value)
|
||||
@@ -83,19 +86,19 @@ namespace Serein.Library
|
||||
|
||||
|
||||
[NodeAction(NodeType.Action, "键值对动态构建对象")]
|
||||
public static object SereinKvDataToObject(Dictionary<string, object> dict,
|
||||
public static object CreateDynamicObjectOfDict(Dictionary<string, object> dict,
|
||||
string classTypeName = "newClass_dynamic",
|
||||
bool IsPrint = false)
|
||||
{
|
||||
if (!DynamicObjectHelper.TryResolve(dict, classTypeName, out var result))
|
||||
{
|
||||
Console.WriteLine("赋值过程中有错误,请检查属性名和类型!");
|
||||
System.Console.WriteLine("赋值过程中有错误,请检查属性名和类型!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsPrint)
|
||||
{
|
||||
Console.WriteLine("创建完成,正在打印结果");
|
||||
System.Console.WriteLine("创建完成,正在打印结果");
|
||||
DynamicObjectHelper.PrintObjectProperties(result);
|
||||
}
|
||||
}
|
||||
@@ -104,7 +107,7 @@ namespace Serein.Library
|
||||
|
||||
|
||||
[NodeAction(NodeType.Action, "设置或更新全局数据")]
|
||||
public static object SereinAddOrUpdateFlowGlobalData(string name, object data)
|
||||
public static object AddOrUpdateFlowGlobalData(string name, object data)
|
||||
{
|
||||
SereinEnv.AddOrUpdateFlowGlobalData(name, data);
|
||||
return data;
|
||||
@@ -631,7 +631,7 @@ namespace Serein.Library
|
||||
|
||||
public string ProjectFileLocation => throw new NotImplementedException();
|
||||
|
||||
public bool IsGlobalInterrupt => throw new NotImplementedException();
|
||||
public bool _IsGlobalInterrupt => throw new NotImplementedException();
|
||||
|
||||
public bool IsControlRemoteEnv => throw new NotImplementedException();
|
||||
|
||||
|
||||
@@ -12,13 +12,12 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 环境方法信息
|
||||
/// </summary>
|
||||
public LibraryMds[] LibraryMds { get; set; }
|
||||
public FlowLibraryInfo[] LibraryMds { get; set; }
|
||||
/// <summary>
|
||||
/// 项目信息
|
||||
/// </summary>
|
||||
public SereinProjectData Project { get; set; }
|
||||
|
||||
// IOC节点对象信息
|
||||
}
|
||||
|
||||
|
||||
@@ -26,16 +25,27 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 程序集相关的方法信息
|
||||
/// </summary>
|
||||
public class LibraryMds
|
||||
public class FlowLibraryInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序集名称
|
||||
/// </summary>
|
||||
public string AssemblyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件名
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 路径
|
||||
/// </summary>
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 相关的方法详情
|
||||
/// </summary>
|
||||
public MethodDetailsInfo[] Mds { get; set; }
|
||||
public List<MethodDetailsInfo> MethodInfos { get; set; }
|
||||
|
||||
}
|
||||
|
||||
@@ -57,7 +67,7 @@ namespace Serein.Library
|
||||
/// 依赖的DLL
|
||||
/// </summary>
|
||||
|
||||
public NodeLibraryInfo[] Librarys { get; set; }
|
||||
public FlowLibraryInfo[] Librarys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 画布集合
|
||||
@@ -89,29 +99,16 @@ namespace Serein.Library
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// 项目依赖的程序集,项目文件相关
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
public class NodeLibraryInfo
|
||||
public class FlowLibraryInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件名
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 路径
|
||||
/// </summary>
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属的程序集名称
|
||||
/// </summary>
|
||||
public string AssemblyName { get; set; }
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 节点信息,项目文件相关
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
@@ -85,9 +86,9 @@ namespace Serein.Library
|
||||
public sealed class NodeActionAttribute : Attribute
|
||||
{
|
||||
public NodeActionAttribute(NodeType methodDynamicType,
|
||||
string methodTips = "",
|
||||
bool scan = true,
|
||||
string lockName = "")
|
||||
string methodTips = "",
|
||||
bool scan = true,
|
||||
string lockName = "")
|
||||
{
|
||||
Scan = scan;
|
||||
MethodDynamicType = methodDynamicType;
|
||||
@@ -110,6 +111,10 @@ namespace Serein.Library
|
||||
/// 暂无意义
|
||||
/// </summary>
|
||||
public string LockName;
|
||||
/// <summary>
|
||||
/// 分组名称,暂无意义
|
||||
/// </summary>
|
||||
public string GroupName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>1.2.1.1</Version>
|
||||
<TargetFrameworks>net8.0;net462</TargetFrameworks>
|
||||
<BaseOutputPath>..\.\.Output</BaseOutputPath>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Title>SereinFow</Title>
|
||||
<Version>1.2.2</Version>
|
||||
<Description>动态节点流、可视化编辑的基本依赖,支持导入C# DLL生成自定义节点,提供二次开发支持,适合用于可视化编程和流程设计</Description>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/fhhyyp/serein-flow</RepositoryUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
|
||||
<TargetFrameworks>net8.0;net462</TargetFrameworks>
|
||||
<BaseOutputPath>..\.\.Output</BaseOutputPath>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<SatelliteResourceLanguages>no</SatelliteResourceLanguages>
|
||||
|
||||
@@ -22,6 +23,22 @@
|
||||
<CompilerGeneratedFilesOutputPath>.\obj\g</CompilerGeneratedFilesOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
|
||||
<NoWarn>1701;1702;1573</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net462|AnyCPU'">
|
||||
<NoWarn>1701;1702;1573</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'">
|
||||
<NoWarn>1701;1702;1573</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net462|AnyCPU'">
|
||||
<NoWarn>1701;1702;1573</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Http\**" />
|
||||
<Compile Remove="Network\**" />
|
||||
@@ -45,7 +62,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
|
||||
|
||||
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.0" />
|
||||
<PackageReference Include="System.IO.Ports" Version="9.0.7" />
|
||||
<PackageReference Include="System.Reactive" Version="6.0.1" />
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Api;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
CanvasInfo = new FlowCanvasDetailsInfo
|
||||
{
|
||||
Name = $"Canvas {_add_canvas_count++}",
|
||||
Name = string.IsNullOrWhiteSpace(canvasName) ? $"Canvas {_add_canvas_count++}" : canvasName,
|
||||
Width = width,
|
||||
Height = height,
|
||||
Guid = Guid.NewGuid().ToString(),
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace Serein.NodeFlow.Env
|
||||
public string ProjectFileLocation => currentFlowEnvironment.EnvName;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsGlobalInterrupt => currentFlowEnvironment.IsGlobalInterrupt;
|
||||
public bool _IsGlobalInterrupt => currentFlowEnvironment._IsGlobalInterrupt;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsControlRemoteEnv => currentFlowEnvironment.IsControlRemoteEnv;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.Library.Utils.SereinExpression;
|
||||
using Serein.NodeFlow.Model.Library;
|
||||
using Serein.NodeFlow.Services;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using System.Text;
|
||||
@@ -38,13 +39,13 @@ namespace Serein.NodeFlow.Env
|
||||
Event = flowEnvironmentEvent;
|
||||
NodeMVVMManagement = nodeMVVMService;
|
||||
FlowEdit = flowEdit;
|
||||
FlowLibraryService = flowLibraryManagement;
|
||||
IOC = sereinIOC;
|
||||
this.flowModelService = flowModelService;
|
||||
FlowControl = flowControl;
|
||||
this.flowOperationService = flowOperationService;
|
||||
this.IsGlobalInterrupt = false;
|
||||
this.flowEnvIOC = sereinIOC;
|
||||
_flowLibraryService = flowLibraryManagement;
|
||||
_flowModelService = flowModelService;
|
||||
_flowOperationService = flowOperationService;
|
||||
_IsGlobalInterrupt = false;
|
||||
_flowEnvIOC = sereinIOC;
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +147,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// <summary>
|
||||
/// 是否全局中断
|
||||
/// </summary>
|
||||
public bool IsGlobalInterrupt { get; set; }
|
||||
public bool _IsGlobalInterrupt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>单例模式IOC容器,内部维护了一个实例字典,默认使用类型的FullName作为Key,如果以“接口-实现类”的方式注册,那么将使用接口类型的FullName作为Key。</para>
|
||||
@@ -185,22 +186,22 @@ namespace Serein.NodeFlow.Env
|
||||
/// <summary>
|
||||
/// local环境的IOC容器,主要用于注册本地环境的服务
|
||||
/// </summary>
|
||||
private ISereinIOC flowEnvIOC;
|
||||
private ISereinIOC _flowEnvIOC;
|
||||
|
||||
/// <summary>
|
||||
/// 通过程序集名称管理动态加载的程序集,用于节点创建提供方法描述,流程运行时提供Emit委托
|
||||
/// </summary>
|
||||
private readonly FlowLibraryService FlowLibraryService;
|
||||
private readonly FlowLibraryService _flowLibraryService;
|
||||
|
||||
/// <summary>
|
||||
/// 流程节点操作服务
|
||||
/// </summary>
|
||||
private readonly FlowOperationService flowOperationService;
|
||||
private readonly FlowOperationService _flowOperationService;
|
||||
|
||||
/// <summary>
|
||||
/// 流程画布、节点实体管理服务
|
||||
/// </summary>
|
||||
private readonly FlowModelService flowModelService;
|
||||
private readonly FlowModelService _flowModelService;
|
||||
|
||||
/* /// <summary>
|
||||
/// 环境加载的节点集合
|
||||
@@ -253,7 +254,7 @@ namespace Serein.NodeFlow.Env
|
||||
public async Task<FlowEnvInfo> GetEnvInfoAsync()
|
||||
{
|
||||
// 获取所有的程序集对应的方法信息(程序集相关的数据)
|
||||
var libraryMdss = this.FlowLibraryService.GetAllLibraryMds().ToArray();
|
||||
var libraryMdss = this._flowLibraryService.GetAllLibraryMds().ToArray();
|
||||
// 获取当前项目的信息(节点相关的数据)
|
||||
var project = await GetProjectInfoAsync(); // 远程连接获取远程环境项目信息
|
||||
SereinEnv.WriteLine(InfoType.INFO, "已将当前环境信息发送到远程客户端");
|
||||
@@ -328,8 +329,6 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
throw;
|
||||
}
|
||||
//
|
||||
//await SetStartNodeAsync("", projectData.StartNode); // 设置起始节点
|
||||
});
|
||||
}
|
||||
|
||||
@@ -428,9 +427,9 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
var projectData = new SereinProjectData()
|
||||
{
|
||||
Librarys = this.FlowLibraryService.GetAllLibraryInfo().ToArray(),
|
||||
Nodes = flowModelService.GetAllNodeModel().Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
|
||||
Canvass = flowModelService.GetAllCanvasModel().Select(canvas => canvas.ToInfo()).ToArray(),
|
||||
Librarys = this._flowLibraryService.GetAllLibraryInfo().ToArray(),
|
||||
Nodes = _flowModelService.GetAllNodeModel().Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
|
||||
Canvass = _flowModelService.GetAllCanvasModel().Select(canvas => canvas.ToInfo()).ToArray(),
|
||||
//StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid,
|
||||
};
|
||||
|
||||
@@ -445,24 +444,12 @@ namespace Serein.NodeFlow.Env
|
||||
/// <returns></returns>
|
||||
public void LoadLibrary(string dllPath)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
#region 检查是否已经加载本地依赖
|
||||
var thisAssembly = typeof(IFlowEnvironment).Assembly;
|
||||
var thisAssemblyName = thisAssembly.GetName().Name;
|
||||
if (!string.IsNullOrEmpty(thisAssemblyName) && FlowLibraryService.GetLibraryMdsOfAssmbly(thisAssemblyName).Count == 0)
|
||||
var libraryInfo = _flowLibraryService.LoadFlowLibrary(dllPath);
|
||||
if (libraryInfo is not null && libraryInfo.MethodInfos.Count > 0)
|
||||
{
|
||||
var tmp = FlowLibraryService.LoadLibraryOfPath(thisAssembly.Location);
|
||||
UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(tmp.Item1, tmp.Item2))); // 通知UI创建dll面板显示
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
(var libraryInfo, var mdInfos) = FlowLibraryService.LoadLibraryOfPath(dllPath);
|
||||
if (mdInfos.Count > 0)
|
||||
{
|
||||
UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(libraryInfo, mdInfos))); // 通知UI创建dll面板显示
|
||||
UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(libraryInfo))); // 通知UI创建dll面板显示
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -471,15 +458,15 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/* /// <summary>
|
||||
/// 加载本地程序集
|
||||
/// </summary>
|
||||
/// <param name="flowLibrary"></param>
|
||||
public void LoadLibrary(FlowLibrary flowLibrary)
|
||||
public void LoadLibrary(FlowLibraryCache flowLibrary)
|
||||
{
|
||||
try
|
||||
{
|
||||
(var libraryInfo, var mdInfos) = FlowLibraryService.LoadLibraryOfPath(flowLibrary);
|
||||
libraryInfo = FlowLibraryService.LoadFlowLibrary(flowLibrary);
|
||||
if (mdInfos.Count > 0)
|
||||
{
|
||||
UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(libraryInfo, mdInfos))); // 通知UI创建dll面板显示
|
||||
@@ -490,7 +477,7 @@ namespace Serein.NodeFlow.Env
|
||||
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件:{ex.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -501,10 +488,10 @@ namespace Serein.NodeFlow.Env
|
||||
public bool TryUnloadLibrary(string assemblyName)
|
||||
{
|
||||
// 获取与此程序集相关的节点
|
||||
var groupedNodes = flowModelService.GetAllNodeModel().Where(node => !string.IsNullOrWhiteSpace(node.MethodDetails.AssemblyName) && node.MethodDetails.AssemblyName.Equals(assemblyName)).ToArray();
|
||||
var groupedNodes = _flowModelService.GetAllNodeModel().Where(node => !string.IsNullOrWhiteSpace(node.MethodDetails.AssemblyName) && node.MethodDetails.AssemblyName.Equals(assemblyName)).ToArray();
|
||||
if (groupedNodes.Length == 0)
|
||||
{
|
||||
var isPass = FlowLibraryService.UnloadLibrary(assemblyName);
|
||||
var isPass = _flowLibraryService.UnloadLibrary(assemblyName);
|
||||
return isPass;
|
||||
}
|
||||
else
|
||||
@@ -584,7 +571,7 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
var model = new FlowCanvasDetails(this);
|
||||
model.LoadInfo(info);
|
||||
flowModelService.AddCanvasModel(model);
|
||||
_flowModelService.AddCanvasModel(model);
|
||||
|
||||
if(UIContextOperation is null)
|
||||
{
|
||||
@@ -608,7 +595,7 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
public bool TryGetMethodDetailsInfo(string assemblyName, string methodName, out MethodDetailsInfo? mdInfo)
|
||||
{
|
||||
var isPass = FlowLibraryService.TryGetMethodDetails(assemblyName, methodName, out var md);
|
||||
var isPass = _flowLibraryService.TryGetMethodDetails(assemblyName, methodName, out var md);
|
||||
if (!isPass || md is null)
|
||||
{
|
||||
mdInfo = null;
|
||||
@@ -633,7 +620,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// <returns></returns>
|
||||
public bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails? delegateDetails)
|
||||
{
|
||||
return FlowLibraryService.TryGetDelegateDetails(assemblyName, methodName, out delegateDetails);
|
||||
return _flowLibraryService.TryGetDelegateDetails(assemblyName, methodName, out delegateDetails);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -648,7 +635,7 @@ namespace Serein.NodeFlow.Env
|
||||
}
|
||||
this.UIContextOperation = uiContextOperation;
|
||||
IOC.Register<UIContextOperation>(() => uiContextOperation).Build();
|
||||
|
||||
OnUIContextOperationSet();
|
||||
}
|
||||
|
||||
|
||||
@@ -713,9 +700,6 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从Guid获取画布
|
||||
/// </summary>
|
||||
@@ -729,7 +713,7 @@ namespace Serein.NodeFlow.Env
|
||||
canvasDetails = null;
|
||||
return false;
|
||||
}
|
||||
return flowModelService.TryGetCanvasModel(nodeGuid, out canvasDetails);
|
||||
return _flowModelService.TryGetCanvasModel(nodeGuid, out canvasDetails);
|
||||
|
||||
}
|
||||
|
||||
@@ -746,7 +730,7 @@ namespace Serein.NodeFlow.Env
|
||||
nodeModel = null;
|
||||
return false;
|
||||
}
|
||||
return flowModelService.TryGetNodeModel(nodeGuid, out nodeModel);
|
||||
return _flowModelService.TryGetNodeModel(nodeGuid, out nodeModel);
|
||||
|
||||
}
|
||||
|
||||
@@ -777,6 +761,20 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 设置了 UIContextOperation 需要立刻执行的方法,用于加载基础库,创建第一个画布。
|
||||
/// </summary>
|
||||
private void OnUIContextOperationSet()
|
||||
{
|
||||
var baseLibrary = _flowLibraryService.LoadBaseLibrary();
|
||||
if (baseLibrary is not null && baseLibrary.MethodInfos.Count > 0)
|
||||
{
|
||||
UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(baseLibrary))); // 通知UI创建dll面板显示
|
||||
}
|
||||
|
||||
// 创建第一个画布
|
||||
FlowEdit.CreateCanvas("Default", 1920, 1080);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -97,9 +97,9 @@ namespace Serein.NodeFlow
|
||||
/// </summary>
|
||||
/// <param name="libraryInfo"></param>
|
||||
/// <returns></returns>
|
||||
public static NodeLibraryInfo ToLibrary(this NodeLibraryInfo libraryInfo)
|
||||
public static FlowLibraryInfo ToLibrary(this FlowLibraryInfo libraryInfo)
|
||||
{
|
||||
return new NodeLibraryInfo
|
||||
return new FlowLibraryInfo
|
||||
{
|
||||
AssemblyName = libraryInfo.AssemblyName,
|
||||
FileName = libraryInfo.FileName,
|
||||
|
||||
@@ -12,52 +12,52 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
namespace Serein.NodeFlow
|
||||
namespace Serein.NodeFlow.Model.Library
|
||||
{
|
||||
public class LibraryMdDd
|
||||
{
|
||||
public MethodDetails MethodDetails { get; }
|
||||
public MethodInfo MethodInfo { get; }
|
||||
public DelegateDetails DelegateDetails { get; }
|
||||
|
||||
public LibraryMdDd(MethodInfo methodInfo, MethodDetails methodDetails, DelegateDetails delegateDetails)
|
||||
{
|
||||
MethodDetails = methodDetails;
|
||||
MethodInfo = methodInfo;
|
||||
DelegateDetails = delegateDetails;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载在流程中的程序集依赖
|
||||
/// </summary>
|
||||
public class FlowLibrary
|
||||
public class FlowLibraryCache
|
||||
{
|
||||
public Assembly Assembly { get; private set; }
|
||||
|
||||
//private readonly Action actionOfUnloadAssmbly;
|
||||
/*, Action actionOfUnloadAssmbly*/
|
||||
//this.actionOfUnloadAssmbly = actionOfUnloadAssmbly;
|
||||
|
||||
public FlowLibrary(Assembly assembly)
|
||||
/// <summary>
|
||||
/// 通过程序集创建一个流程库实例
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
public FlowLibraryCache(Assembly assembly)
|
||||
{
|
||||
this.Assembly = assembly;
|
||||
this.FullName = Path.GetFileName(Assembly.Location);
|
||||
|
||||
this.FilePath = Assembly.Location;
|
||||
Assembly = assembly;
|
||||
FullName = Path.GetFileName(Assembly.Location);
|
||||
FilePath = Assembly.Location;
|
||||
}
|
||||
|
||||
public FlowLibrary(Assembly assembly,
|
||||
/// <summary>
|
||||
/// 通过动态程序集和文件路径创建一个流程库实例
|
||||
/// </summary>
|
||||
/// <param name="dynamicAssembly"></param>
|
||||
/// <param name="filePath"></param>
|
||||
public FlowLibraryCache(Assembly dynamicAssembly,
|
||||
string filePath)
|
||||
{
|
||||
this.Assembly = assembly;
|
||||
this.FullName = Path.GetFileName(filePath); ;
|
||||
this.FilePath = filePath;
|
||||
Assembly = dynamicAssembly;
|
||||
FullName = Path.GetFileName(filePath); ;
|
||||
FilePath = filePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 程序集本身
|
||||
/// </summary>
|
||||
public Assembly Assembly { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序集全名
|
||||
/// </summary>
|
||||
public string FullName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序集文件路径
|
||||
/// </summary>
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -65,60 +65,33 @@ namespace Serein.NodeFlow
|
||||
/// Key : 方法名称
|
||||
/// Value :方法详情
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, MethodDetails> MethodDetailss { get; } = new ConcurrentDictionary<string, MethodDetails>();
|
||||
public ConcurrentDictionary<string, MethodInfo> MethodInfos { get; } = new ConcurrentDictionary<string, MethodInfo>();
|
||||
public Dictionary<string, MethodDetails> MethodDetailss { get; } = new Dictionary<string, MethodDetails>();
|
||||
|
||||
/// <summary>
|
||||
/// 管理通过Emit动态构建的委托
|
||||
/// Key :方法名称
|
||||
/// Value :方法详情
|
||||
/// 加载程序集时创建的方法信息
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<string, DelegateDetails> DelegateDetailss { get; } = new ConcurrentDictionary<string, DelegateDetails>();
|
||||
public Dictionary<string, MethodInfo> MethodInfos { get; } = new Dictionary<string, MethodInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// 记录不同的注册时机需要自动创建全局唯一实例的类型信息
|
||||
/// <para>缓存节点方法通Emit委托</para>
|
||||
/// <para>Key :方法名称</para>
|
||||
/// <para>Value :方法详情</para>
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<RegisterSequence, List<Type>> RegisterTypes { get; } = new ConcurrentDictionary<RegisterSequence, List<Type>>();
|
||||
|
||||
public Dictionary<string, DelegateDetails> DelegateDetailss { get; } = new Dictionary<string, DelegateDetails>();
|
||||
|
||||
/// <summary>
|
||||
/// 卸载当前程序集以及附带的所有信息
|
||||
/// 用于流程启动时,在不同阶段(Init_Loading_Loaded)需要创建实例的类型信息
|
||||
/// </summary>
|
||||
public void Upload()
|
||||
{
|
||||
DelegateDetailss.Clear();
|
||||
RegisterTypes.Clear();
|
||||
MethodDetailss.Clear();
|
||||
//actionOfUnloadAssmbly?.Invoke();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转为依赖信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public NodeLibraryInfo ToInfo()
|
||||
{
|
||||
var assemblyName = Assembly.GetName().Name;
|
||||
return new NodeLibraryInfo
|
||||
{
|
||||
AssemblyName = assemblyName,
|
||||
FileName = this.FullName,
|
||||
FilePath = this.FilePath,
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
public Dictionary<RegisterSequence, List<Type>> RegisterTypes { get; } = new Dictionary<RegisterSequence, List<Type>>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 动态加载程序集
|
||||
/// </summary>
|
||||
/// <param name="assembly">程序集本身</param>
|
||||
/// <returns></returns>
|
||||
public bool LoadAssembly()
|
||||
public bool LoadFlowMethod()
|
||||
{
|
||||
Assembly assembly = this.Assembly;
|
||||
Assembly assembly = Assembly;
|
||||
|
||||
#region 检查入参
|
||||
|
||||
@@ -132,7 +105,7 @@ namespace Serein.NodeFlow
|
||||
try
|
||||
{
|
||||
types = assembly.GetTypes().ToList(); // 获取程序集中的所有类型
|
||||
if (types.Count < 0) // 防止动态程序集中没有类型信息?
|
||||
if (types.Count <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -143,7 +116,7 @@ namespace Serein.NodeFlow
|
||||
var loaderExceptions = ex.LoaderExceptions;
|
||||
foreach (var loaderException in loaderExceptions)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.ERROR, loaderException?.Message);
|
||||
SereinEnv.WriteLine(InfoType.ERROR, "加载失败 : " + loaderException?.Message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -160,8 +133,7 @@ namespace Serein.NodeFlow
|
||||
// Type : 具有 DynamicFlowAttribute 标记的类型
|
||||
// string : 类型元数据 DynamicFlowAttribute 特性中的 Name 属性
|
||||
|
||||
types = types.Where(type => type.GetCustomAttribute<DynamicFlowAttribute>() is DynamicFlowAttribute dynamicFlowAttribute
|
||||
&& dynamicFlowAttribute.Scan).ToList();
|
||||
types = types.Where(type => type.GetCustomAttribute<DynamicFlowAttribute>() is DynamicFlowAttribute df && df.Scan).ToList();
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
@@ -208,20 +180,16 @@ namespace Serein.NodeFlow
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// 简单排序一下
|
||||
//detailss = detailss.OrderBy(k => k.MethodDetails.MethodName,).ToList();
|
||||
|
||||
|
||||
|
||||
// 简单排序一下
|
||||
detailss.Sort((a, b) => string.Compare(a.MethodDetails.MethodName, b.MethodDetails.MethodName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
foreach (var item in detailss)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "loading method : " + item.MethodDetails.MethodName);
|
||||
SereinEnv.WriteLine(InfoType.INFO, "加载方法 : " + item.MethodDetails.MethodName);
|
||||
|
||||
}
|
||||
|
||||
//detailss.Sort((a, b) => string.Compare());
|
||||
|
||||
|
||||
#region 加载成功,缓存所有方法、委托的信息
|
||||
foreach (var item in detailss)
|
||||
{
|
||||
@@ -253,6 +221,36 @@ namespace Serein.NodeFlow
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 卸载当前程序集以及附带的所有信息
|
||||
/// </summary>
|
||||
public void Unload()
|
||||
{
|
||||
DelegateDetailss.Clear();
|
||||
MethodInfos.Clear();
|
||||
RegisterTypes.Clear();
|
||||
MethodDetailss.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转为依赖信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public FlowLibraryInfo ToInfo()
|
||||
{
|
||||
var assemblyName = Assembly.GetName().Name;
|
||||
var mdInfos = MethodDetailss.Values.Select(x => x.ToInfo()).ToList();
|
||||
mdInfos.Sort((a, b) => string.Compare(a.MethodName, b.MethodName, StringComparison.OrdinalIgnoreCase));
|
||||
return new FlowLibraryInfo
|
||||
{
|
||||
AssemblyName = assemblyName,
|
||||
FileName = FullName,
|
||||
FilePath = FilePath,
|
||||
MethodInfos = mdInfos.ToList(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
20
NodeFlow/Model/Library/LibraryMdDd.cs
Normal file
20
NodeFlow/Model/Library/LibraryMdDd.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Serein.Library;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Serein.NodeFlow.Model.Library
|
||||
{
|
||||
public class LibraryMdDd
|
||||
{
|
||||
public MethodDetails MethodDetails { get; }
|
||||
public MethodInfo MethodInfo { get; }
|
||||
public DelegateDetails DelegateDetails { get; }
|
||||
|
||||
public LibraryMdDd(MethodInfo methodInfo, MethodDetails methodDetails, DelegateDetails delegateDetails)
|
||||
{
|
||||
MethodDetails = methodDetails;
|
||||
MethodInfo = methodInfo;
|
||||
DelegateDetails = delegateDetails;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -231,7 +231,7 @@ namespace Serein.NodeFlow.Model
|
||||
|
||||
var returnType = sereinScript.ParserScript(Script, argTypes); // 开始解析获取程序主节点
|
||||
MethodDetails.ReturnType = returnType;
|
||||
var scriptMethodInfo = sereinScript.ConvertCSharpCode(methodName, argTypes);
|
||||
var scriptMethodInfo = sereinScript.ConvertCSharpCode(methodName, argTypes);
|
||||
return scriptMethodInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -42,18 +42,18 @@ namespace Serein.NodeFlow.Model.Operation
|
||||
{
|
||||
if (!flowModelService.ContainsCanvasModel(CanvasGuid))
|
||||
{
|
||||
flowEnvironment.WriteLine(Library.InfoType.INFO, $"节点取出失败,目标画布不存在[{NodeGuid}]");
|
||||
flowEnvironment.WriteLine(Serein.Library.InfoType.WARN, $"节点取出失败,目标画布不存在[{NodeGuid}]");
|
||||
return false;
|
||||
}
|
||||
// 获取目标节点与容器节点
|
||||
if (!flowModelService.TryGetNodeModel(NodeGuid, out var nodeModel))
|
||||
{
|
||||
flowEnvironment.WriteLine(Library.InfoType.INFO, $"节点取出失败,目标节点不存在[{NodeGuid}]");
|
||||
flowEnvironment.WriteLine(Serein.Library.InfoType.WARN, $"节点取出失败,目标节点不存在[{NodeGuid}]");
|
||||
return false;
|
||||
}
|
||||
if (nodeModel.ContainerNode is not INodeContainer containerNode)
|
||||
{
|
||||
flowEnvironment.WriteLine(Library.InfoType.INFO, $"节点取出失败,节点并非容器节点[{nodeModel.Guid}]");
|
||||
flowEnvironment.WriteLine(Serein.Library.InfoType.WARN, $"节点取出失败,节点并非容器节点[{nodeModel.Guid}]");
|
||||
return false;
|
||||
}
|
||||
Node = nodeModel;
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Serein.NodeFlow.Model.Operation
|
||||
|
||||
// 节点与画布互相绑定
|
||||
nodeModel.CanvasDetails = flowCanvasDetails;
|
||||
flowCanvasDetails.Nodes.Add(nodeModel);
|
||||
flowCanvasDetails.Nodes = [..flowCanvasDetails.Nodes, nodeModel];
|
||||
|
||||
flowModelService.AddNodeModel(nodeModel);
|
||||
this.flowNode = nodeModel;
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Script.Node;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Serein.NodeFlow.Model.Operation
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>1.2.1</Version>
|
||||
<Version>1.2.2</Version>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -52,6 +52,7 @@
|
||||
<Compile Remove="Tool\Attribute.cs" />
|
||||
<Compile Remove="Tool\DynamicTool.cs" />
|
||||
<Compile Remove="Tool\ExpressionHelper.cs" />
|
||||
<Compile Remove="Tool\FlowLibraryAssemblyContext2.cs" />
|
||||
<Compile Remove="Tool\NodeModelBaseFunc.cs" />
|
||||
<Compile Remove="Tool\TcsSignal.cs" />
|
||||
<Compile Remove="Tool\ToCSharpCodeHelper.cs" />
|
||||
@@ -69,6 +70,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.13.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.6" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
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.Runtime.Loader;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
@@ -28,54 +29,95 @@ namespace Serein.NodeFlow.Services
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存所有加载了的程序集
|
||||
/// 缓存流程依赖
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, FlowLibrary> _myFlowLibrarys = new ConcurrentDictionary<string, FlowLibrary>();
|
||||
private readonly ConcurrentDictionary<string, FlowLibraryCache> _flowLibraryCaches = new ConcurrentDictionary<string, FlowLibraryCache>();
|
||||
|
||||
|
||||
private readonly ConcurrentDictionary<string, FlowLibraryAssemblyContext> _flowLibraryAssemblyContexts
|
||||
= new ConcurrentDictionary<string, FlowLibraryAssemblyContext>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载类库
|
||||
/// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
|
||||
/// </summary>
|
||||
/// <param name="libraryfilePath"></param>
|
||||
/// <returns></returns>
|
||||
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(string libraryfilePath)
|
||||
private bool CheckBaseLibrary(string libraryfilePath, out string baseLibraryPath)
|
||||
{
|
||||
|
||||
var dir = Path.GetDirectoryName(libraryfilePath); // 获取目录路径
|
||||
var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
|
||||
var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);
|
||||
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;
|
||||
baseLibraryPath = string.Empty;
|
||||
return false;
|
||||
}
|
||||
baseLibraryPath = sereinFlowBaseLibraryPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载类库
|
||||
/// 加载基础依赖
|
||||
/// </summary>
|
||||
/// <param name="flowLibrary"></param>
|
||||
/// <returns></returns>
|
||||
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(FlowLibrary flowLibrary)
|
||||
public FlowLibraryInfo LoadBaseLibrary()
|
||||
{
|
||||
return LoadFlowLibrary(flowLibrary);
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载流程依赖
|
||||
/// </summary>
|
||||
/// <param name="libraryfilePath"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 卸载类库
|
||||
/// </summary>
|
||||
@@ -83,11 +125,11 @@ namespace Serein.NodeFlow.Services
|
||||
/// <returns></returns>
|
||||
public bool UnloadLibrary(string assemblyName)
|
||||
{
|
||||
if (_myFlowLibrarys.Remove(assemblyName, out var flowLibrary))
|
||||
if (_flowLibraryCaches.Remove(assemblyName, out var flowLibrary))
|
||||
{
|
||||
try
|
||||
{
|
||||
flowLibrary.Upload(); // 尝试卸载
|
||||
flowLibrary.Unload(); // 尝试卸载
|
||||
flowLibrary = null;
|
||||
return true;
|
||||
}
|
||||
@@ -104,6 +146,8 @@ namespace Serein.NodeFlow.Services
|
||||
}
|
||||
}
|
||||
|
||||
#region 获取流程依赖的相关方法
|
||||
|
||||
/// <summary>
|
||||
/// 获取方法描述
|
||||
/// </summary>
|
||||
@@ -118,7 +162,7 @@ namespace Serein.NodeFlow.Services
|
||||
methodInfo = null;
|
||||
return false;
|
||||
}
|
||||
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary)
|
||||
if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary)
|
||||
&& flowLibrary.MethodInfos.TryGetValue(methodName, out methodInfo))
|
||||
{
|
||||
return true;
|
||||
@@ -130,7 +174,7 @@ namespace Serein.NodeFlow.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// 获取方法描述
|
||||
/// </summary>
|
||||
/// <param name="assemblyName">程序集名称</param>
|
||||
@@ -139,7 +183,7 @@ namespace Serein.NodeFlow.Services
|
||||
/// <returns>是否获取成功</returns>
|
||||
public bool TryGetMethodDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodDetails md)
|
||||
{
|
||||
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary)
|
||||
if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary)
|
||||
&& flowLibrary.MethodDetailss.TryGetValue(methodName, out md))
|
||||
{
|
||||
return true;
|
||||
@@ -160,7 +204,7 @@ namespace Serein.NodeFlow.Services
|
||||
/// <returns>是否获取成功</returns>
|
||||
public bool TryGetDelegateDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out DelegateDetails dd)
|
||||
{
|
||||
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary)
|
||||
if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary)
|
||||
&& flowLibrary.DelegateDetailss.TryGetValue(methodName, out dd))
|
||||
{
|
||||
return true;
|
||||
@@ -182,7 +226,7 @@ namespace Serein.NodeFlow.Services
|
||||
{
|
||||
List<MethodDetails> mds = [];
|
||||
|
||||
foreach (var library in _myFlowLibrarys.Values)
|
||||
foreach (var library in _flowLibraryCaches.Values)
|
||||
{
|
||||
var t_mds = library.MethodDetailss.Values.Where(it => it.MethodDynamicType == nodeType).ToList();
|
||||
mds.AddRange(t_mds);
|
||||
@@ -197,7 +241,7 @@ namespace Serein.NodeFlow.Services
|
||||
public Dictionary<RegisterSequence, List<Type>> GetaAutoRegisterType()
|
||||
{
|
||||
Dictionary<RegisterSequence, List<Type>> rsTypes = new Dictionary<RegisterSequence, List<Type>>();
|
||||
foreach (var library in _myFlowLibrarys.Values)
|
||||
foreach (var library in _flowLibraryCaches.Values)
|
||||
{
|
||||
foreach (var kv in library.RegisterTypes)
|
||||
{
|
||||
@@ -220,28 +264,26 @@ namespace Serein.NodeFlow.Services
|
||||
/// <returns></returns>
|
||||
public List<MethodDetails> GetLibraryMdsOfAssmbly(string assemblyName)
|
||||
{
|
||||
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary))
|
||||
if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary))
|
||||
{
|
||||
return flowLibrary.MethodDetailss.Values.ToList();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有方法信息,用于保存项目时调用
|
||||
/// 获取流程方法信息,用于保存项目时调用
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<LibraryMds> GetAllLibraryMds()
|
||||
public List<FlowLibraryInfo> GetAllLibraryMds()
|
||||
{
|
||||
List<LibraryMds> mds = new List<LibraryMds>();
|
||||
foreach (FlowLibrary library in _myFlowLibrarys.Values)
|
||||
List<FlowLibraryInfo> mds = new List<FlowLibraryInfo>();
|
||||
foreach (FlowLibraryCache library in _flowLibraryCaches.Values)
|
||||
{
|
||||
var tmp = new LibraryMds
|
||||
var tmp = new FlowLibraryInfo
|
||||
{
|
||||
AssemblyName = library.FullName,
|
||||
Mds = library.MethodDetailss.Values.Select(md => md.ToInfo()).ToArray()
|
||||
MethodInfos = library.MethodDetailss.Values.Select(md => md.ToInfo()).ToList()
|
||||
};
|
||||
mds.Add(tmp);
|
||||
}
|
||||
@@ -253,11 +295,11 @@ namespace Serein.NodeFlow.Services
|
||||
/// 序列化当前项目的依赖信息、节点信息,用于远程登录的场景,需要将依赖信息从本地(受控端)发送到远程(主控端)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<NodeLibraryInfo> GetAllLibraryInfo()
|
||||
public List<FlowLibraryInfo> GetAllLibraryInfo()
|
||||
{
|
||||
return _myFlowLibrarys.Values.Select(library => library.ToInfo()).ToList();
|
||||
return _flowLibraryCaches.Values.Select(library => library.ToInfo()).ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 功能性方法
|
||||
|
||||
@@ -266,132 +308,7 @@ namespace Serein.NodeFlow.Services
|
||||
/// </summary>
|
||||
public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Library)}.dll";
|
||||
|
||||
//private (NodeLibraryInfo, List<MethodDetailsInfo>) 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<MethodDetailsInfo>) 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<MethodDetailsInfo> mdInfos = flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList();
|
||||
mdInfos.Sort((a, b) => string.Compare(a.MethodName, b.MethodName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
(NodeLibraryInfo, List<MethodDetailsInfo>) result = (flowLibrary.ToInfo(), mdInfos);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流程依赖加载
|
||||
/// </summary>
|
||||
public class FlowLibraryAssemblyContext : AssemblyLoadContext
|
||||
{
|
||||
private readonly AssemblyDependencyResolver _resolver;
|
||||
|
||||
/// <summary>
|
||||
/// 创建新的加载上下文
|
||||
/// </summary>
|
||||
/// <param name="sereinFlowLibraryPath">类库路径</param>
|
||||
/// <param name="name"></param>
|
||||
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 = 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);
|
||||
|
||||
// }
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Emit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Tool
|
||||
{
|
||||
|
||||
59
NodeFlow/Tool/FlowLibraryAssemblyContext.cs
Normal file
59
NodeFlow/Tool/FlowLibraryAssemblyContext.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
|
||||
namespace Serein.NodeFlow.Tool
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程依赖加载
|
||||
/// </summary>
|
||||
public class FlowLibraryAssemblyContext : AssemblyLoadContext
|
||||
{
|
||||
private readonly AssemblyDependencyResolver _resolver;
|
||||
|
||||
/// <summary>
|
||||
/// 创建新的加载上下文
|
||||
/// </summary>
|
||||
/// <param name="baseLibraryPath">流程基础依赖类库路径</param>
|
||||
/// <param name="name"></param>
|
||||
public FlowLibraryAssemblyContext(string baseLibraryPath, string name) : base(name, isCollectible: true)
|
||||
{
|
||||
_resolver = new AssemblyDependencyResolver(baseLibraryPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载指定的程序集
|
||||
/// </summary>
|
||||
/// <param name="assemblyName"></param>
|
||||
/// <returns></returns>
|
||||
protected override Assembly? Load(AssemblyName assemblyName)
|
||||
{
|
||||
string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); // 加载程序集
|
||||
if (!string.IsNullOrEmpty(assemblyPath))
|
||||
{
|
||||
var assembly = 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
|
||||
}
|
||||
}
|
||||
}
|
||||
44
NodeFlow/Tool/FlowLibraryAssemblyContext2.cs
Normal file
44
NodeFlow/Tool/FlowLibraryAssemblyContext2.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.NodeFlow.Model.Library
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 流程依赖加载
|
||||
/// </summary>
|
||||
public class FlowLibraryAssemblyContext : AssemblyLoadContext
|
||||
{
|
||||
private readonly AssemblyDependencyResolver _resolver;
|
||||
|
||||
/// <summary>
|
||||
/// 创建新的加载上下文
|
||||
/// </summary>
|
||||
/// <param name="sereinFlowLibraryPath">类库路径</param>
|
||||
/// <param name="name"></param>
|
||||
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 = Default.LoadFromAssemblyPath(assemblyPath);
|
||||
//var assembly = LoadFromAssemblyPath(assemblyPath);
|
||||
return assembly;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Default.Assemblies.FirstOrDefault(x => x.FullName == assemblyName.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,4 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Serein.Library.Utils;
|
||||
|
||||
namespace Serein.Extend.NewtonsoftJson
|
||||
{
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<BaseOutputPath>..\.\.Output</BaseOutputPath>
|
||||
|
||||
<Title>为 SereinFlow 提供的 JSON 扩展</Title>
|
||||
<Version>1.0.0</Version>
|
||||
<Description>通过 NewtonsoftJson 实现JSON门户扩展,用于解决 Serein.Proto.* 项目下需要 JSON 序列化与反序列化的场景</Description>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<!--<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0">
|
||||
|
||||
@@ -10,10 +10,10 @@ namespace Serein.Proto.Modbus
|
||||
/// 创建 Modbus 客户端实例
|
||||
/// </summary>
|
||||
/// <param name="connectionString">
|
||||
/// 连接字符串格式:
|
||||
/// TCP示例:"tcp:192.168.1.100:502"
|
||||
/// UCP示例:"ucp:192.168.1.100:502"
|
||||
/// RTU示例:"rtu:COM3:9600:1" (格式:rtu:串口名:波特率:从站地址)
|
||||
/// <para>连接字符串格式: </para>
|
||||
/// <para>TCP示例:"tcp:192.168.1.100:502" </para>
|
||||
/// <para>UCP示例:"ucp:192.168.1.100:502" </para>
|
||||
/// <para>RTU示例:"rtu:COM3:9600:1" (格式:rtu:串口名:波特率:从站地址) </para>
|
||||
/// </param>
|
||||
public static IModbusClient Create(string connectionString)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<BaseOutputPath>..\.\.Output</BaseOutputPath>
|
||||
|
||||
<Title>全异步Modbus协议客户端工具包</Title>
|
||||
<Version>1.0.0</Version>
|
||||
<Description>提供TCP、UDP、RTU三种方式客户端;创建方式:IModbusClient client = ModbusClientFactory.Create...;</Description>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<BaseOutputPath>..\.\.Output</BaseOutputPath>
|
||||
|
||||
<Title>基于Json数据载体的WebSocket交互工具包</Title>
|
||||
<Version>1.0.0</Version>
|
||||
<Description>基于Json数据载体的WebSocket交互工具包</Description>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Script.Node;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script
|
||||
namespace Serein.Script
|
||||
{
|
||||
internal static class NodeInterpreterExtension
|
||||
{
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<BaseOutputPath>..\.\.Output</BaseOutputPath>
|
||||
|
||||
<Title>基于AST实现的脚本语言</Title>
|
||||
<Version>1.0.0</Version>
|
||||
<Description>使用了Emit构造委托缓存调用,性能客观。提供了类型推导、转换C#代码功能。用于流程图中脚本处理,也可在其他地方进行使用。</Description>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/fhhyyp/serein-flow</RepositoryUrl>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -18,7 +27,16 @@
|
||||
<None Remove="TestExpression\**" />
|
||||
<None Remove="Tool\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
<None Include="..\README.md">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Node\ExpressionNode.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library;
|
||||
using Serein.Script.Node;
|
||||
using Serein.Script.Node.FlowControl;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script
|
||||
{
|
||||
|
||||
@@ -269,9 +269,8 @@ namespace Serein.Script
|
||||
}
|
||||
ASTNode tempNode = peekToken3.Type switch
|
||||
{
|
||||
TokenType.Dot => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
|
||||
TokenType.Semicolon => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
|
||||
TokenType.ParenthesisRight => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
|
||||
TokenType.Dot or TokenType.Semicolon or TokenType.ParenthesisRight =>
|
||||
ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
|
||||
TokenType.SquareBracketsLeft => ParseCollectionIndexNode(source), // 获取集合中的元素 source[index]....
|
||||
TokenType.ParenthesisLeft => ParseMemberFunctionCallNode(source), // 获取需要调用的方法 source(arg1,arg2...)...
|
||||
_ => throw new Exception($"无法从对象获取成员,当前Token类型为 {peekToken.Type}。")
|
||||
@@ -963,11 +962,9 @@ namespace Serein.Script
|
||||
var peekToken3 = _lexer.PeekToken();
|
||||
ASTNode tempNode = peekToken3.Type switch
|
||||
{
|
||||
TokenType.Comma => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
|
||||
TokenType.Operator => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
|
||||
TokenType.Dot => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
|
||||
TokenType.Semicolon => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
|
||||
TokenType.ParenthesisRight => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
|
||||
TokenType.Comma or TokenType.Operator or TokenType.Dot or TokenType.Semicolon or TokenType.ParenthesisRight
|
||||
=> ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
|
||||
|
||||
TokenType.SquareBracketsLeft => ParseCollectionIndexNode(source), // 获取集合中的元素 source[index]....
|
||||
TokenType.ParenthesisLeft => ParseMemberFunctionCallNode(source), // 获取需要调用的方法 source(arg1,arg2...)...
|
||||
_ => throw new Exception($"无法从对象获取成员,当前Token : {peekToken.ToString()}。")
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library;
|
||||
using Serein.Workbench.Api;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using Serein.Workbench.Themes;
|
||||
using Serein.Workbench.Views;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library;
|
||||
using Serein.NodeFlow;
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.NodeFlow.Model.Library;
|
||||
using Serein.Workbench.Themes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Serein.Workbench.Node.ViewModel
|
||||
@@ -71,9 +63,9 @@ public class FlowLibrary
|
||||
});
|
||||
}
|
||||
|
||||
private static void OnCompileComplete(FlowLibrary flowLibrary)
|
||||
private static void OnCompileComplete(FlowLibraryCache flowLibrary)
|
||||
{
|
||||
var loadResult = flowLibrary.LoadAssembly(); // 动态编译完成后加载程序集
|
||||
var loadResult = flowLibrary.LoadFlowMethod(); // 动态编译完成后加载程序集
|
||||
if (!loadResult)
|
||||
{
|
||||
return ;
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace Serein.Workbench.Services
|
||||
SereinEnv.WriteLine(InfoType.INFO, "项目文件保存路径:" + savePath);
|
||||
for (int index = 0; index < project.Librarys.Length; index++)
|
||||
{
|
||||
NodeLibraryInfo? library = project.Librarys[index];
|
||||
FlowLibraryInfo? library = project.Librarys[index];
|
||||
string sourceFilePath = new Uri(library.FilePath).LocalPath; // 源文件夹
|
||||
string targetDir = System.IO.Path.Combine(librarySavePath, library.AssemblyName); // 目标文件夹
|
||||
if (!Path.Exists(targetDir))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Microsoft.Win32;
|
||||
using Serein.NodeFlow;
|
||||
using Serein.NodeFlow.Model.Library;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -34,7 +34,7 @@ namespace Serein.Workbench.Themes
|
||||
/// <summary>
|
||||
/// 编译成功回调
|
||||
/// </summary>
|
||||
public Action<FlowLibrary> OnCompileComplete { get; set; }
|
||||
public Action<FlowLibraryCache> OnCompileComplete { get; set; }
|
||||
public DynamicCompilerView()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -132,7 +132,7 @@ namespace Serein.Workbench.Themes
|
||||
var path = textboxAssemblyName.Text;
|
||||
Assembly assembly = _compiler.Compile(code, path);
|
||||
|
||||
FlowLibrary flowLibrary = new FlowLibrary(assembly, path);
|
||||
FlowLibraryCache flowLibrary = new FlowLibraryCache(assembly, path);
|
||||
|
||||
if (assembly != null)
|
||||
{
|
||||
|
||||
@@ -19,13 +19,13 @@ namespace Serein.Workbench.ViewModels
|
||||
private readonly IFlowEEForwardingService flowEEForwardingService;
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<FlowLibraryInfo> flowLibraryInfos;
|
||||
private ObservableCollection<Models.FlowLibraryInfo> flowLibraryInfos;
|
||||
|
||||
public FlowLibrarysViewModel(IFlowEEForwardingService flowEEForwardingService,IFlowEnvironment flowEnvironment)
|
||||
{
|
||||
this.flowEEForwardingService = flowEEForwardingService;
|
||||
this.flowEnvironment = flowEnvironment;
|
||||
FlowLibraryInfos = new ObservableCollection<FlowLibraryInfo>();
|
||||
FlowLibraryInfos = new ObservableCollection<Models.FlowLibraryInfo>();
|
||||
flowEEForwardingService.DllLoad += FlowEEForwardingService_OnDllLoad;
|
||||
}
|
||||
/// <summary>
|
||||
@@ -48,15 +48,15 @@ namespace Serein.Workbench.ViewModels
|
||||
private void FlowEEForwardingService_OnDllLoad(Library.Api.LoadDllEventArgs eventArgs)
|
||||
{
|
||||
if (!eventArgs.IsSucceed) return;
|
||||
List<MethodDetailsInfo> mds = eventArgs.MethodDetailss;
|
||||
NodeLibraryInfo libraryInfo = eventArgs.NodeLibraryInfo;
|
||||
List<MethodDetailsInfo> mds = eventArgs.NodeLibraryInfo.MethodInfos.ToList() ;
|
||||
Library.FlowLibraryInfo libraryInfo = eventArgs.NodeLibraryInfo;
|
||||
|
||||
var methodInfo = new ObservableCollection<MethodDetailsInfo>();
|
||||
foreach (var md in mds)
|
||||
{
|
||||
methodInfo.Add(md);
|
||||
}
|
||||
var flInfo = new FlowLibraryInfo
|
||||
var flInfo = new Models.FlowLibraryInfo
|
||||
{
|
||||
LibraryName = libraryInfo.AssemblyName,
|
||||
FilePath = libraryInfo.FilePath,
|
||||
|
||||
Reference in New Issue
Block a user