diff --git a/Library/Entity/DelegateDetails.cs b/Library/Entity/DelegateDetails.cs index 6818620..824e820 100644 --- a/Library/Entity/DelegateDetails.cs +++ b/Library/Entity/DelegateDetails.cs @@ -27,5 +27,35 @@ namespace Serein.Library.Entity private EmitMethodType _emitMethodType; public Delegate EmitDelegate { get => _emitDelegate; } public EmitMethodType EmitMethodType { get => _emitMethodType; } + + public async Task Invoke(object instance, object[] args) + { + object result = null; + try + { + if (EmitMethodType == EmitMethodType.HasResultTask && EmitDelegate is Func> hasResultTask) + { + result = await hasResultTask(instance, args); + } + else if (EmitMethodType == EmitMethodType.Task && EmitDelegate is Func task) + { + await task.Invoke(instance, args); + result = null; + } + else if (EmitMethodType == EmitMethodType.Func && EmitDelegate is Func func) + { + result = func.Invoke(instance, args); + } + else + { + throw new NotImplementedException("创建了非预期委托(应该不会出现)"); + } + return result; + } + catch + { + throw; + } + } } } diff --git a/Library/Network/WebSocket/Attribute.cs b/Library/Network/WebSocket/Attribute.cs index 827d2c7..fec73bb 100644 --- a/Library/Network/WebSocket/Attribute.cs +++ b/Library/Network/WebSocket/Attribute.cs @@ -7,26 +7,69 @@ using System.Net.WebSockets; namespace Serein.Library.Network.WebSocketCommunication { + /// + /// 标记该类是处理模板,需要获取WebSocketServer/WebSocketClient了实例后,使用(Server/Client).MsgHandleHelper.AddModule()进行添加。 + /// 处理模板需要继承 ISocketHandleModule 接口,否则WebSocket接受到数据时,将无法进行调用相应的处理模板。 + /// 使用方式: + /// [AutoSocketModule(ThemeKey = "theme", DataKey = "data")] + /// public class PlcSocketService : ISocketHandleModule + /// 类中方法示例:void AddUser(string name,age 35) + /// Json示例:{ "theme":"AddUser", //【ThemeKey】 + /// "data": { // 【DataKey】 + /// "name":"张三", + /// "age":35, } } + /// WebSocket中收到以上该Json时,通过ThemeKey获取到"AddUser",然后找到AddUser()方法,并将"data"作为数据对象,取出相应数据作为入参(args:"张三",35)进行调用(如果有) + /// + /// + /// + [AttributeUsage(AttributeTargets.Class)] + public sealed class AutoSocketModuleAttribute : Attribute + { + public string ThemeKey; + public string DataKey; + } + + + /// + /// 作用:WebSocket中处理Json时,将通过Json中ThemeKey 对应的内容(ThemeValue)自动路由到相应方法进行处理。 + /// 如果没有显式设置ThemeValue,将默认使用方法名称作为ThemeValue。 + /// 如果没有显式设置IsReturnValue标记为false,当方法顺利完成(没有抛出异常,且返回对象非null),会自动转为json文本发送回去 + /// 如果返回类型为Task或Task<TResult>,将会自动等待异步完成并获取结果(无法处理Task<Task<TResult>>的情况)。 + /// 如果返回了值类型,会自动装箱为引用对象。 + /// 如果有方法执行过程中发送消息的需求,请在入参中声明以下类型的成员,调用时将传入发送消息的委托。 + /// Action<string> : 发送文本内容。 + /// Action<object> : 会自动将对象解析为Json字符串,发送文本内容。 + /// Action<dynamic> : 会自动将对象解析为Json字符串,发送文本内容。 + /// Func<string,Task> : 异步发送文本内容。 + /// Func<object,Task> : 会自动将对象解析为Json字符串,异步发送文本内容。 + /// Func<dynamic,Task> : 会自动将对象解析为Json字符串,异步发送文本内容。 + /// [AttributeUsage(AttributeTargets.Method)] public sealed class AutoSocketHandleAttribute : Attribute { + /// + /// 描述Json业务字段,如果不设置,将默认使用方法名称。 + /// public string ThemeValue = string.Empty; + /// + /// 标记方法执行完成后是否需要将结果发送。 + /// 但以下情况将不会发送: + /// 1.返回类型为void + /// 2.返回类型为Task + /// 3.返回了null + /// 补充:如果返回类型是Task<TResult> + /// 会进行异步等待,当Task结束后,自动获取TResult进行发送(请避免Task<Task<TResult>>诸如此类的Task泛型嵌套) + /// public bool IsReturnValue = true; - //public Type DataType; } - - public class SocketHandleModel + + internal class SocketHandleModel { public string ThemeValue { get; set; } = string.Empty; public bool IsReturnValue { get; set; } = true; } - [AttributeUsage(AttributeTargets.Class)] - public sealed class AutoSocketModuleAttribute : Attribute - { - public string JsonDataField; - public string JsonThemeField; - } + } diff --git a/Library/Network/WebSocket/Handle/MyHandleConfig.cs b/Library/Network/WebSocket/Handle/WebSocketHandleConfig.cs similarity index 94% rename from Library/Network/WebSocket/Handle/MyHandleConfig.cs rename to Library/Network/WebSocket/Handle/WebSocketHandleConfig.cs index 057dca0..ae87755 100644 --- a/Library/Network/WebSocket/Handle/MyHandleConfig.cs +++ b/Library/Network/WebSocket/Handle/WebSocketHandleConfig.cs @@ -15,14 +15,14 @@ using System.Threading.Tasks; namespace Serein.Library.Network.WebSocketCommunication.Handle { - public class MyHandleConfig + public class WebSocketHandleConfig { private readonly Delegate EmitDelegate; private readonly EmitHelper.EmitMethodType EmitMethodType; private Action> OnExceptionTracking; - public MyHandleConfig(SocketHandleModel model,ISocketControlBase instance, MethodInfo methodInfo, Action> onExceptionTracking) + internal WebSocketHandleConfig(SocketHandleModel model,ISocketHandleModule instance, MethodInfo methodInfo, Action> onExceptionTracking) { EmitMethodType = EmitHelper.CreateDynamicMethod(methodInfo,out EmitDelegate); this.Model = model; @@ -36,7 +36,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle } private SocketHandleModel Model; - private ISocketControlBase Instance; + private ISocketHandleModule Instance; public Guid HandleGuid { get; } private string[] ParameterName; private Type[] ParameterType; @@ -51,7 +51,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle var argName = ParameterName[i]; if (type.IsGenericType) { - if (type.IsAssignableFrom(typeof(Func))) + if (type.IsAssignableFrom(typeof(Func))) { args[i] = new Func(async data => { diff --git a/Library/Network/WebSocket/Handle/MyHandleModule.cs b/Library/Network/WebSocket/Handle/WebSocketHandleModule.cs similarity index 76% rename from Library/Network/WebSocket/Handle/MyHandleModule.cs rename to Library/Network/WebSocket/Handle/WebSocketHandleModule.cs index 471ee71..4904ead 100644 --- a/Library/Network/WebSocket/Handle/MyHandleModule.cs +++ b/Library/Network/WebSocket/Handle/WebSocketHandleModule.cs @@ -8,9 +8,9 @@ using System.Threading.Tasks; namespace Serein.Library.Network.WebSocketCommunication.Handle { - public class MyHandleModule + public class WebSocketHandleModule { - public MyHandleModule(string ThemeJsonKey, string DataJsonKey) + public WebSocketHandleModule(string ThemeJsonKey, string DataJsonKey) { this.ThemeJsonKey = ThemeJsonKey; this.DataJsonKey = DataJsonKey; @@ -21,17 +21,17 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle - public ConcurrentDictionary MyHandleConfigs = new ConcurrentDictionary(); - public void AddHandleConfigs(SocketHandleModel model, ISocketControlBase instance, MethodInfo methodInfo + public ConcurrentDictionary MyHandleConfigs = new ConcurrentDictionary(); + internal void AddHandleConfigs(SocketHandleModel model, ISocketHandleModule instance, MethodInfo methodInfo , Action> onExceptionTracking) { if (!MyHandleConfigs.ContainsKey(model.ThemeValue)) { - var myHandleConfig = new MyHandleConfig(model,instance, methodInfo, onExceptionTracking); + var myHandleConfig = new WebSocketHandleConfig(model,instance, methodInfo, onExceptionTracking); MyHandleConfigs[model.ThemeValue] = myHandleConfig; } } - public bool ResetConfig(ISocketControlBase socketControlBase) + public bool ResetConfig(ISocketHandleModule socketControlBase) { foreach (var kv in MyHandleConfigs.ToArray()) { diff --git a/Library/Network/WebSocket/Handle/SocketMsgHandleHelper.cs b/Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs similarity index 80% rename from Library/Network/WebSocket/Handle/SocketMsgHandleHelper.cs rename to Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs index 7e076b4..7130379 100644 --- a/Library/Network/WebSocket/Handle/SocketMsgHandleHelper.cs +++ b/Library/Network/WebSocket/Handle/WebSocketMsgHandleHelper.cs @@ -20,13 +20,13 @@ using System.Security.Cryptography; namespace Serein.Library.Network.WebSocketCommunication.Handle { - public class SocketMsgHandleHelper + public class WebSocketMsgHandleHelper { /// /// (Theme Name ,Data Name) - HandleModule /// - public ConcurrentDictionary<(string, string), MyHandleModule> MyHandleModuleDict - = new ConcurrentDictionary<(string, string), MyHandleModule>(); + public ConcurrentDictionary<(string, string), WebSocketHandleModule> MyHandleModuleDict + = new ConcurrentDictionary<(string, string), WebSocketHandleModule>(); private Action> _onExceptionTracking; /// @@ -34,18 +34,18 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle /// public event Action> OnExceptionTracking; - private MyHandleModule AddMyHandleModule(string themeKeyName, string dataKeyName) + private WebSocketHandleModule AddMyHandleModule(string themeKeyName, string dataKeyName) { var key = (themeKeyName, dataKeyName); if (!MyHandleModuleDict.TryGetValue(key, out var myHandleModule)) { - myHandleModule = new MyHandleModule(themeKeyName, dataKeyName); + myHandleModule = new WebSocketHandleModule(themeKeyName, dataKeyName); MyHandleModuleDict[key] = myHandleModule; } return myHandleModule; } - public void RemoteModule(ISocketControlBase socketControlBase) + public void RemoteModule(ISocketHandleModule socketControlBase) { var type = socketControlBase.GetType(); var moduleAttribute = type.GetCustomAttribute(); @@ -53,8 +53,8 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle { return; } - var themeKeyName = moduleAttribute.JsonThemeField; - var dataKeyName = moduleAttribute.JsonDataField; + var themeKeyName = moduleAttribute.ThemeKey; + var dataKeyName = moduleAttribute.DataKey; var key = (themeKeyName, dataKeyName); if (MyHandleModuleDict.TryGetValue(key, out var myHandleModules)) { @@ -63,7 +63,14 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle } } - public void AddModule(ISocketControlBase socketControlBase, Action> onExceptionTracking) + + + /// + /// 添加 + /// + /// + /// + public void AddModule(ISocketHandleModule socketControlBase, Action> onExceptionTracking) { var type = socketControlBase.GetType(); var moduleAttribute = type.GetCustomAttribute(); @@ -72,8 +79,8 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle return; } - var themeKey = moduleAttribute.JsonThemeField; - var dataKey = moduleAttribute.JsonDataField; + var themeKey = moduleAttribute.ThemeKey; + var dataKey = moduleAttribute.DataKey; var handlemodule = AddMyHandleModule(themeKey, dataKey); var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) diff --git a/Library/Network/WebSocket/SocketControlBase.cs b/Library/Network/WebSocket/SocketControlBase.cs index 428b996..7a409c1 100644 --- a/Library/Network/WebSocket/SocketControlBase.cs +++ b/Library/Network/WebSocket/SocketControlBase.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace Serein.Library.Network.WebSocketCommunication { - public interface ISocketControlBase + public interface ISocketHandleModule { Guid HandleGuid { get; } } diff --git a/Library/Network/WebSocket/WebSocketServer.cs b/Library/Network/WebSocket/WebSocketServer.cs index 0bc642f..0471a7e 100644 --- a/Library/Network/WebSocket/WebSocketServer.cs +++ b/Library/Network/WebSocket/WebSocketServer.cs @@ -14,11 +14,12 @@ using System.Threading.Tasks; namespace Serein.Library.Network.WebSocketCommunication { + [AutoRegister] public class WebSocketServer { - public SocketMsgHandleHelper MsgHandleHelper { get; } = new SocketMsgHandleHelper(); + public WebSocketMsgHandleHelper MsgHandleHelper { get; } = new WebSocketMsgHandleHelper(); - HttpListener listener; + private HttpListener listener; public async Task StartAsync(string url) { listener = new HttpListener(); diff --git a/Library/NodeAttribute.cs b/Library/NodeAttribute.cs index ee97485..16b652e 100644 --- a/Library/NodeAttribute.cs +++ b/Library/NodeAttribute.cs @@ -4,7 +4,11 @@ using System; namespace Serein.Library.Attributes { /// - /// 表示该属性为自动注入依赖项 + /// 表示该属性为自动注入依赖项。 + /// 使用场景:构造函数中存在互相依赖的情况 + /// 例如ServiceA类构造函数中需要传入ServiceB,ServiceB类构造函数中也需要传入ServiceA + /// 这种情况会导致流程启动时,IOC容器无法注入构造函数并创建类型,导致启动失败。 + /// 解决方法:从ServiceA类的构造函数中移除ServiceB类型的入参,将该类型更改为公开可见的可写属性成员ServiceB serviceB{get;set;},并在该属性上标记[AutoInjection]特性 /// [AttributeUsage(AttributeTargets.Property)] public sealed class AutoInjectionAttribute : Attribute @@ -25,8 +29,17 @@ namespace Serein.Library.Attributes /// FlowLoading, } + + /// - /// 表示该类自动注册(单例模式) + /// 启动流程时,会将标记了该特性的类自动注册到IOC容器中,从而无需手动进行注册绑定。 + /// 流程启动后,IOC容器会进行5次注册绑定。 + /// 第1次注册绑定:初始化所有节点所属的类([DynamicFlow]标记的类)。 + /// 第2次注册绑定:※初始化所有[AutoRegister(Class=FlowInit)]的类。 + /// 第3次注册绑定:调用所有Init节点后,进行注册绑定。 + /// 第4次注册绑定:※初始化所有[AutoRegister(Class=FlowLoading)]的类 + /// 第5次注册绑定:调用所有Load节点后,进行注册绑定。 + /// 需要注意的是,在第1次进行注册绑定的过程中,如果类的构造函数存在入参,那么也会将入参自动创建实例并托管到IOC容器中。 /// [AttributeUsage(AttributeTargets.Class)] public sealed class AutoRegisterAttribute : Attribute @@ -39,7 +52,7 @@ namespace Serein.Library.Attributes } /// - /// 用来判断一个类是否需要注册并构建节点 + /// 表示该类中存在节点信息 /// [AttributeUsage(AttributeTargets.Class)] public class DynamicFlowAttribute : Attribute @@ -49,14 +62,21 @@ namespace Serein.Library.Attributes Name = name; Scan = scan; } + /// + /// 补充名称,不影响运行流程 + /// public string Name { get; set; } + /// + /// 如果设置为false,将忽略该类 + /// public bool Scan { get; set; } = true; } /// - /// 生成的节点类型 + /// 表示该方法将会生成节点,或是加入到流程运行中 + /// 如果是Task类型的返回值,将会自动进行等待 /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class NodeActionAttribute : Attribute @@ -71,10 +91,25 @@ namespace Serein.Library.Attributes MethodTips = methodTips; LockName = lockName; } + /// + /// 如果设置为false时将不会生成节点信息 + /// public bool Scan; + /// + /// 类似于注释的效果 + /// public string MethodTips; + /// + /// 标记节点行为 + /// public NodeType MethodDynamicType; + /// + /// 显示标注方法返回类型,不影响运行逻辑(用于表示触发器触发后返回的数据) + /// public Type ReturnType; + /// + /// 暂无意义 + /// public string LockName; } diff --git a/Net462DllTest/Main.cs b/Net462DllTest/Main.cs index 578a642..5d3f330 100644 --- a/Net462DllTest/Main.cs +++ b/Net462DllTest/Main.cs @@ -8,17 +8,20 @@ namespace Net462DllTest.Properties { /* 理想的项目架构: + + 每一种功能拆分为新的项目 + FlowEnv - LoginControl: - LoginControl + LoginControl ↙ ↘ - (View-Interaction) (Node-Interaction) - ↓ ↕ - View ←→ ViewModel ←→ Trigger ← SingleEnum - ↓ - Model - · DataChanged → Trigger + (View-Interaction) (Node-Interaction) + ↓ ↕ + View ←→ ViewModel ←→ Trigger ← SingleEnum + ↓ ↓ ↖ + ↓ ↓ ↖ + Node →→→ Model → Event(OnDataChanged) 视图驱动触发器,触发器驱动数据。 diff --git a/Net462DllTest/Web/PlcSocketService.cs b/Net462DllTest/Web/PlcSocketService.cs index 3233991..0c5f976 100644 --- a/Net462DllTest/Web/PlcSocketService.cs +++ b/Net462DllTest/Web/PlcSocketService.cs @@ -18,8 +18,8 @@ namespace Net462DllTest.Web [DynamicFlow("[PlcSocketService]")] [AutoRegister] - [AutoSocketModule(JsonThemeField = "theme", JsonDataField = "data")] - public class PlcSocketService : ISocketControlBase + [AutoSocketModule(ThemeKey = "theme", DataKey = "data")] + public class PlcSocketService : ISocketHandleModule { public Guid HandleGuid { get; } = new Guid(); @@ -101,6 +101,14 @@ namespace Net462DllTest.Web } + [AutoSocketHandle] + public object ReadVar(PlcVarName varName) + { + var result = MyPlc.Read(varName); + Console.WriteLine($"获取变量成功:({varName})\t result = {result}"); + return result; + } + [AutoSocketHandle(IsReturnValue = false)] public SiemensPlcDevice PlcInit(SiemensVersion version = SiemensVersion.None, string ip = "192.168.10.100", @@ -134,13 +142,7 @@ namespace Net462DllTest.Web return MyPlc; } - [AutoSocketHandle] - public object ReadVar(PlcVarName varName) - { - var result = MyPlc.Read(varName); - Console.WriteLine($"获取变量成功:({varName})\t result = {result}"); - return result; - } + [AutoSocketHandle(IsReturnValue = false)] public SiemensPlcDevice WriteVar(object value, PlcVarName varName) @@ -149,9 +151,12 @@ namespace Net462DllTest.Web return MyPlc; } - public PlcVarModelDataProxy BatchReadVar() + [AutoSocketHandle] + public PlcVarModelDataProxy BatchReadVar(Func send) { + send("开始读取"); MyPlc.BatchRefresh(); + send("读取完成"); return plcVarModelDataProxy; } diff --git a/NodeFlow/Base/NodeModelBaseFunc.cs b/NodeFlow/Base/NodeModelBaseFunc.cs index 1eb3d11..ff7e3ae 100644 --- a/NodeFlow/Base/NodeModelBaseFunc.cs +++ b/NodeFlow/Base/NodeModelBaseFunc.cs @@ -204,11 +204,7 @@ namespace Serein.NodeFlow.Base md.ActingInstance ??= context.Env.IOC.Get(md.ActingInstanceType); object instance = md.ActingInstance; - //bool haveParameter = md.ExplicitDatas.Length > 0; - //bool haveResult = md.ReturnType != typeof(void); - // Type? taskResult = null; - //bool isTask = md.ReturnType is not null && MethodDetailsHelper.IsGenericTask(md.ReturnType, out taskResult); - //bool isTaskHaveResult = taskResult is not null; + object? result = null; //Console.WriteLine($"(isTask, isTaskHaveResult):{(isTask, isTaskHaveResult)}"); @@ -217,49 +213,7 @@ namespace Serein.NodeFlow.Base // Action/Func([方法作用的实例],[可能的参数值],[可能的返回值]) object?[]? args = GetParameters(context, this, md); - var delType = dd.EmitMethodType; - var del = dd.EmitDelegate; - if (delType == EmitHelper.EmitMethodType.HasResultTask && del is Func> hasResultTask) - { - result = await hasResultTask(instance, args); - } - else if (delType == EmitHelper.EmitMethodType.Task && del is Func task) - { - await task.Invoke(instance, args); - result = null; - } - else if (delType == EmitHelper.EmitMethodType.Func && del is Func func) - { - result = func.Invoke(instance, args); - } - else - { - throw new NotImplementedException("构造委托无法正确调用"); - } - - //if (isTask) - //{ - // // 异步方法(因为返回了Task,所以排除Action<>委托的可能) - // result = (haveParameter, isTaskHaveResult) switch - // { - // (false, false) => await ExecutionAsync((Func)del, instance), // 调用节点方法,返回方法传回类型 - // (true, false) => await ExecutionAsync((Func)del, instance, parameters), // 调用节点方法,获取入参参数,返回方法返回类型 - // (false, true) => await ExecutionAsync((Func>)del, instance), // 调用节点方法,返回方法传回类型 - // (true, true) => await ExecutionAsync((Func>)del, instance, parameters), // 调用节点方法,获取入参参数,返回方法返回类型 - // }; - //} - //else - //{ - // // 非异步方法 - // result = (haveParameter, haveResult) switch - // { - // (false, false) => Execution((Action)del, instance), // 调用节点方法,返回null - // (true, false) => Execution((Action)del, instance, parameters), // 调用节点方法,返回null - // (false, true) => Execution((Func)del, instance), // 调用节点方法,返回方法传回类型 - // (true, true) => Execution((Func)del, instance, parameters), // 调用节点方法,获取入参参数,返回方法返回类型 - // }; - //} - + result = await dd.Invoke(md.ActingInstance, args); NextOrientation = ConnectionType.IsSucceed; return result; } @@ -273,47 +227,6 @@ namespace Serein.NodeFlow.Base } - #region 节点转换的委托类型 - public static object? Execution(Action del, object instance) - { - del.Invoke(instance); - return null; - } - public static object? Execution(Action del, object instance, object?[]? parameters) - { - del.Invoke(instance, parameters); - return null; - } - public static object? Execution(Func del, object instance) - { - return del.Invoke(instance); - } - public static object? Execution(Func del, object instance, object?[]? parameters) - { - return del.Invoke(instance, parameters); - } - - - public static async Task ExecutionAsync(Func del, object instance) - { - await del.Invoke(instance); - return null; - } - public static async Task ExecutionAsync(Func del, object instance, object?[]? parameters) - { - await del.Invoke(instance, parameters); - return null; - } - public static async Task ExecutionAsync(Func> del, object instance) - { - return await del.Invoke(instance); - } - public static async Task ExecutionAsync(Func> del, object instance, object?[]? parameters) - { - return await del.Invoke(instance, parameters); - } - #endregion - /// /// 获取对应的参数数组 diff --git a/NodeFlow/FlowEnvironment.cs b/NodeFlow/FlowEnvironment.cs index 4af428d..40734cb 100644 --- a/NodeFlow/FlowEnvironment.cs +++ b/NodeFlow/FlowEnvironment.cs @@ -984,10 +984,10 @@ namespace Serein.NodeFlow { continue; } - var methods = MethodDetailsHelper.GetMethodsToProcess(type); + var methods = NodeMethodDetailsHelper.GetMethodsToProcess(type); foreach(var method in methods) { - (var md, var del) = MethodDetailsHelper.CreateMethodDetails(type, method, assemblyName); + (var md, var del) = NodeMethodDetailsHelper.CreateMethodDetails(type, method, assemblyName); if(md is null || del is null) { Console.WriteLine($"无法加载方法信息:{assemblyName}-{type}-{method}"); diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs index 12fd09c..9c6127a 100644 --- a/NodeFlow/FlowStarter.cs +++ b/NodeFlow/FlowStarter.cs @@ -73,7 +73,7 @@ namespace Serein.NodeFlow /// /// 结束运行时需要执行的方法 /// - private Action ExitAction { get; set; } = null; + private Func ExitAction { get; set; } = null; /// /// 运行的上下文 /// @@ -136,7 +136,6 @@ namespace Serein.NodeFlow #endregion - #region 选择运行环境的上下文 // 判断使用哪一种流程上下文 @@ -234,7 +233,8 @@ namespace Serein.NodeFlow { throw new Exception("不存在对应委托"); } - ((Func)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]); + await dd.Invoke(md.ActingInstance, [Context]); + //((Func)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]); } Context.Env.IOC.Build(); // 绑定初始化时注册的类型 @@ -254,14 +254,15 @@ namespace Serein.NodeFlow { throw new Exception("不存在对应委托"); } + await dd.Invoke(md.ActingInstance, [Context]); //((Action)del).Invoke(md.ActingInstance, [Context]); - ((Func)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]); + //((Func)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]); } Context.Env.IOC.Build(); // 预防有人在加载时才注册类型,再绑定一次 #endregion #region 设置流程退出时的回调函数 - ExitAction = () => + ExitAction = async () => { env.IOC.Run(web => { web?.Stop(); @@ -273,7 +274,8 @@ namespace Serein.NodeFlow { throw new Exception("不存在对应委托"); } - ((Func)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]); + await dd.Invoke(md.ActingInstance, [Context]); + //((Func)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]); } TerminateAllGlobalFlipflop(); diff --git a/NodeFlow/Model/CompositeConditionNode.cs b/NodeFlow/Model/CompositeConditionNode.cs index 4e02700..3eea781 100644 --- a/NodeFlow/Model/CompositeConditionNode.cs +++ b/NodeFlow/Model/CompositeConditionNode.cs @@ -24,13 +24,12 @@ namespace Serein.NodeFlow.Model /// /// /// - //public override object? Executing(IDynamicContext context) - public override Task ExecutingAsync(IDynamicContext context) + public override async Task ExecutingAsync(IDynamicContext context) { // 条件区域中遍历每个条件节点 foreach (SingleConditionNode? node in ConditionNodes) { - var state = Judge(context, node); + var state = await JudgeAsync(context, node); NextOrientation = state; // 每次判读完成后,设置区域后继方向为判断结果 if (state != ConnectionType.IsSucceed) { @@ -42,11 +41,11 @@ namespace Serein.NodeFlow.Model } - private ConnectionType Judge(IDynamicContext context, SingleConditionNode node) + private async Task JudgeAsync(IDynamicContext context, SingleConditionNode node) { try { - node.ExecutingAsync(context); + await node.ExecutingAsync(context); return node.NextOrientation; } catch (Exception ex) diff --git a/NodeFlow/Model/SingleFlipflopNode.cs b/NodeFlow/Model/SingleFlipflopNode.cs index 62a7502..88c8bea 100644 --- a/NodeFlow/Model/SingleFlipflopNode.cs +++ b/NodeFlow/Model/SingleFlipflopNode.cs @@ -40,32 +40,46 @@ namespace Serein.NodeFlow.Model object instance = md.ActingInstance; try { - Task flipflopTask; var args = GetParameters(context, this, md); - var delType = dd.EmitMethodType; - var del = dd.EmitDelegate; - if (delType == EmitHelper.EmitMethodType.HasResultTask && del is Func> hasResultTask) + var result = await dd.Invoke(md.ActingInstance, args); + if (result is IFlipflopContext flipflopContext) { - var flipflopTaskObj = await hasResultTask(instance, args); - if(flipflopTaskObj is IFlipflopContext flipflopContext) + NextOrientation = flipflopContext.State.ToContentType(); + if (flipflopContext.TriggerData is null || flipflopContext.TriggerData.Type == Library.NodeFlow.Tool.TriggerType.Overtime) { - NextOrientation = flipflopContext.State.ToContentType(); - if (flipflopContext.TriggerData is null || flipflopContext.TriggerData.Type == Library.NodeFlow.Tool.TriggerType.Overtime) - { - throw new FlipflopException(base.MethodDetails.MethodName + "触发器超时触发。Guid" + base.Guid); - } - return flipflopContext.TriggerData.Value; - } - else - { - throw new FlipflopException("触发器节点返回了非预期的类型", true, FlipflopException.CancelClass.Flow); + throw new FlipflopException(base.MethodDetails.MethodName + "触发器超时触发。Guid" + base.Guid); } + return flipflopContext.TriggerData.Value; } else { - throw new FlipflopException("触发器节点构造了非预期的委托", true, FlipflopException.CancelClass.Flow); + throw new FlipflopException("触发器节点返回了非预期的类型", true, FlipflopException.CancelClass.Flow); } - + // Task flipflopTask; + //var delType = dd.EmitMethodType; + //var del = dd.EmitDelegate; + //if (delType == EmitHelper.EmitMethodType.HasResultTask && del is Func> hasResultTask) + //{ + // var flipflopTaskObj = await hasResultTask(instance, args); + // if(flipflopTaskObj is IFlipflopContext flipflopContext) + // { + // NextOrientation = flipflopContext.State.ToContentType(); + // if (flipflopContext.TriggerData is null || flipflopContext.TriggerData.Type == Library.NodeFlow.Tool.TriggerType.Overtime) + // { + // throw new FlipflopException(base.MethodDetails.MethodName + "触发器超时触发。Guid" + base.Guid); + // } + // return flipflopContext.TriggerData.Value; + // } + // else + // { + // throw new FlipflopException("触发器节点返回了非预期的类型", true, FlipflopException.CancelClass.Flow); + // } + //} + //else + //{ + // throw new FlipflopException("触发器节点构造了非预期的委托", true, FlipflopException.CancelClass.Flow); + //} + } catch (FlipflopException ex) { diff --git a/NodeFlow/Tool/MethodDetailsHelper.cs b/NodeFlow/Tool/NodeMethodDetailsHelper.cs similarity index 99% rename from NodeFlow/Tool/MethodDetailsHelper.cs rename to NodeFlow/Tool/NodeMethodDetailsHelper.cs index ee1fbc9..83d3a61 100644 --- a/NodeFlow/Tool/MethodDetailsHelper.cs +++ b/NodeFlow/Tool/NodeMethodDetailsHelper.cs @@ -11,7 +11,7 @@ using System.Text.RegularExpressions; namespace Serein.NodeFlow.Tool; -public static class MethodDetailsHelper +public static class NodeMethodDetailsHelper { /// @@ -57,7 +57,7 @@ public static class MethodDetailsHelper public static (MethodDetails?, DelegateDetails?) CreateMethodDetails(Type type, MethodInfo method, string assemblyName) { var attribute = method.GetCustomAttribute(); - if(attribute is null) + if(attribute is null || attribute.Scan == false) { return (null, null); } diff --git a/Serein.FlowRemoteManagement/FlowRemoteManagement.cs b/Serein.FlowRemoteManagement/FlowRemoteManagement.cs index 9c5c741..bb739ae 100644 --- a/Serein.FlowRemoteManagement/FlowRemoteManagement.cs +++ b/Serein.FlowRemoteManagement/FlowRemoteManagement.cs @@ -24,6 +24,7 @@ namespace SereinFlowRemoteManagement { environment.IOC.Register(); } + [NodeAction(NodeType.Loading)] public void Loading(IDynamicContext context) { @@ -34,8 +35,11 @@ namespace SereinFlowRemoteManagement SereinProjectData projectData = environment.SaveProject(); } - + public void GetAllNodeInfo() + { + + } } }