重写了Web Api的逻辑,用Emit构造委托加速API处理

This commit is contained in:
fengjiayi
2024-10-10 16:49:37 +08:00
parent d1b9a3f28f
commit 99f82d5772
25 changed files with 792 additions and 628 deletions

View File

@@ -8,7 +8,6 @@ using Serein.Library.Attributes;
using Serein.Library.Enums;
using Serein.Library.Ex;
using Serein.Library.Framework.NodeFlow;
using Serein.Library.Network.WebSocketCommunication;
using Serein.Library.NodeFlow.Tool;
using Serein.Library.Web;
using System;
@@ -16,64 +15,33 @@ using System.Threading.Tasks;
namespace Net462DllTest.LogicControl
{
[AutoRegister]
[DynamicFlow("[SiemensPlc]")]
public class PlcLogicControl
[DynamicFlow("[SiemensPlc]")]
public class PlcLogicControl
{
public Guid HandleGuid { get; } = new Guid();
private readonly SiemensPlcDevice MyPlc;
private readonly PlcVarModelDataProxy plcVarModelDataProxy;
public PlcLogicControl(SiemensPlcDevice MyPlc,
PlcVarModelDataProxy plcVarModelDataProxy)
PlcVarModelDataProxy plcVarModelDataProxy)
{
this.MyPlc = MyPlc;
this.plcVarModelDataProxy = plcVarModelDataProxy;
}
#region 退
[NodeAction(NodeType.Init)]
public void Init(IDynamicContext context)
{
context.Env.IOC.Register<WebSocketServer>();
context.Env.IOC.Register<WebSocketClient>();
context.Env.IOC.Register<IRouter, Router>();
context.Env.IOC.Register<WebApiServer>();
}
#region
[NodeAction(NodeType.Loading)] // Loading 初始化完成已注入依赖项,可以开始逻辑上的操作
public void Loading(IDynamicContext context)
{
// 注册控制器
context.Env.IOC.Run<IRouter, WebApiServer>((router, apiServer) => {
router.RegisterController(typeof(FlowController));
apiServer.Start("http://*:8089/"); // 开启 Web Api 服务
});
context.Env.IOC.Run<WebSocketServer>(async (socketServer) => {
// socketServer.RegisterModuleInstance(userService);
await socketServer.StartAsync("http://localhost:5005/"); // 开启 Web Socket 监听
});
context.Env.IOC.Run<WebSocketClient>(async client => {
await client.ConnectAsync("ws://localhost:5005/"); // 连接到服务器
});
}
[NodeAction(NodeType.Exit)] // 流程结束时自动执行
public void Exit(IDynamicContext context)
{
context.Env.IOC.Run<WebApiServer>((apiServer) =>
{
apiServer?.Stop(); // 关闭 Web 服务
});
context.Env.IOC.Run<WebSocketServer>((socketServer) =>
{
socketServer?.Stop(); // 关闭 Web 服务
});
MyPlc.Close();
MyPlc.CancelAllTasks();
}
@@ -120,13 +88,14 @@ namespace Net462DllTest.LogicControl
}
[NodeAction(NodeType.Action, "PLC初始化")]
public SiemensPlcDevice PlcInit(SiemensVersion version = SiemensVersion.None,
string ip = "192.168.10.100",
int port = 102)
{
//MyPlc.Model.Set(PlcVarName.DoorVar,1);
//MyPlc.Model.Value.SpaceNum = 1;
MyPlc.Model.Set(PlcVarName.DoorVar,(Int16)1);
MyPlc.Model.Get(PlcVarName.DoorVar);
if (MyPlc.Client is null)
{
try
@@ -155,6 +124,7 @@ namespace Net462DllTest.LogicControl
return MyPlc;
}
[NodeAction(NodeType.Action, "PLC获取变量")]
public object ReadVar(PlcVarName varName)
{
@@ -163,6 +133,7 @@ namespace Net462DllTest.LogicControl
return result;
}
[NodeAction(NodeType.Action, "PLC写入变量")]
public SiemensPlcDevice WriteVar(object value, PlcVarName varName)
{
@@ -171,10 +142,13 @@ namespace Net462DllTest.LogicControl
}
[NodeAction(NodeType.Action, "批量读取")]
public void BatchReadVar()
public PlcVarModelDataProxy BatchReadVar()
{
MyPlc.BatchRefresh();
return plcVarModelDataProxy;
}
[NodeAction(NodeType.Action, "开启定时刷新")]
public void OpenTimedRefresh()
{

View File

@@ -35,7 +35,7 @@ namespace Net462DllTest.LogicControl
#region
[NodeAction(NodeType.Flipflop, "等待视图命令", ReturnType = typeof(int))]
public async Task<IFlipflopContext> WaitTask(CommandSignal command = CommandSignal.Command_1)
public async Task<IFlipflopContext> WaitTask(CommandSignal command)
{
try
{

View File

@@ -92,7 +92,7 @@
<DependentUpon>TestFormView.cs</DependentUpon>
</Compile>
<Compile Include="Web\FlowController.cs" />
<Compile Include="Web\UserService.cs" />
<Compile Include="Web\PlcSocketService.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\DynamicControl\SereinFlow\Library.Framework\Serein.Library.Framework.csproj">

View File

@@ -17,6 +17,7 @@ using System.Collections.Concurrent;
using System.Threading.Tasks;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrackBar;
using System.Linq;
using Serein.Library.Network.WebSocketCommunication;
namespace Net462DllTest.Trigger
{

View File

@@ -11,11 +11,13 @@ namespace Net462DllTest.Utils
{
public interface IGSModel<TKey, TModel>
{
TModel Value { get; set; }
//TModel Value { get; set; }
void Set(TKey tEnum, object value);
object Get(TKey tEnum);
}
/// <summary>
/// 通过 Emit 创建 set/get 委托
/// </summary>
@@ -23,7 +25,8 @@ namespace Net462DllTest.Utils
where TKey : struct, Enum
where TModel : class
{
public TModel Value { get; set; }
private TModel Value;
public GSModel(TModel Model)
{
this.Value = Model;
@@ -32,55 +35,6 @@ namespace Net462DllTest.Utils
private readonly Dictionary<TKey, Action<TModel, object>> _setterCache = new Dictionary<TKey, Action<TModel, object>>();
private readonly Dictionary<TKey, Func<TModel, object>> _getterCache = new Dictionary<TKey, Func<TModel, object>>();
// 动态创建调用Setter方法
private Action<TModel, object> CreateSetter(PropertyInfo property)
{
var method = new DynamicMethod("Set" + property.Name, null, new[] { typeof(TModel), typeof(object) }, true);
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // 加载实例PlcVarValue
il.Emit(OpCodes.Ldarg_1); // 加载值object
if (property.PropertyType.IsValueType)
{
il.Emit(OpCodes.Unbox_Any, property.PropertyType); // 解箱并转换为值类型
}
else
{
il.Emit(OpCodes.Castclass, property.PropertyType); // 引用类型转换
}
il.Emit(OpCodes.Callvirt, property.GetSetMethod()); // 调用属性的Setter方法
il.Emit(OpCodes.Ret); // 返回
return (Action<TModel, object>)method.CreateDelegate(typeof(Action<TModel, object>));
}
/// <summary>
/// 动态创建调用Getter方法
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private Func<TModel, object> CreateGetter(PropertyInfo property)
{
var method = new DynamicMethod("Get" + property.Name, typeof(object), new[] { typeof(TModel) }, true);
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // 加载实例PlcVarValue
il.Emit(OpCodes.Callvirt, property.GetGetMethod()); // 调用属性的Getter方法
if (property.PropertyType.IsValueType)
{
il.Emit(OpCodes.Box, property.PropertyType); // 值类型需要装箱
}
il.Emit(OpCodes.Ret); // 返回
return (Func<TModel, object>)method.CreateDelegate(typeof(Func<TModel, object>));
}
public void Set(TKey tEnum, object value)
{
if (!_setterCache.TryGetValue(tEnum, out var setter))
@@ -89,7 +43,6 @@ namespace Net462DllTest.Utils
if (property == null)
{
_setterCache[tEnum] = (s, o) => throw new ArgumentException($"没有对应的Model属性{{{tEnum}");
//throw new ArgumentException($"Property not found for {plcVarEnum}");
}
else
{
@@ -141,5 +94,67 @@ namespace Net462DllTest.Utils
}
return null;
}
// 动态创建调用Setter方法
private Action<TModel, object> CreateSetter(PropertyInfo property)
{
var method = new DynamicMethod("Set" + property.Name, null, new[] { typeof(TModel), typeof(object) }, true);
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // 加载实例PlcVarValue
il.Emit(OpCodes.Ldarg_1); // 加载值object
if (property.PropertyType.IsValueType)
{
il.Emit(OpCodes.Unbox_Any, property.PropertyType); // 解箱并转换为值类型
}
else
{
il.Emit(OpCodes.Castclass, property.PropertyType); // 引用类型转换
}
il.Emit(OpCodes.Callvirt, property.GetSetMethod()); // 调用属性的Setter方法
il.Emit(OpCodes.Ret); // 返回
return (Action<TModel, object>)method.CreateDelegate(typeof(Action<TModel, object>));
}
/// <summary>
/// 动态创建调用Getter方法
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private Func<TModel, object> CreateGetter(PropertyInfo property)
{
var method = new DynamicMethod("Get" + property.Name, typeof(object), new[] { typeof(TModel) }, true);
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // 加载实例PlcVarValue
il.Emit(OpCodes.Callvirt, property.GetGetMethod()); // 调用属性的Getter方法
if (property.PropertyType.IsValueType)
{
il.Emit(OpCodes.Box, property.PropertyType); // 值类型需要装箱
}
il.Emit(OpCodes.Ret); // 返回
return (Func<TModel, object>)method.CreateDelegate(typeof(Func<TModel, object>));
}
}
}

View File

@@ -49,7 +49,7 @@ namespace Net462DllTest
private void FromWorkBenchView_FormClosing(object sender, FormClosingEventArgs e)
{
ViewModel.CommandCloseForm.Execute();
ViewModel.CommandCloseForm?.Execute();
}
private void button2_Click(object sender, EventArgs e)

View File

@@ -30,10 +30,8 @@ namespace Net462DllTest.ViewModel
}
}
[AutoSocketModule(JsonThemeField = "theme", JsonDataField = "data")]
public class FromWorkBenchViewModel : INotifyPropertyChanged, ISocketControlBase
public class FromWorkBenchViewModel : INotifyPropertyChanged
{
public Guid HandleGuid { get; } = new Guid();
private readonly SiemensPlcDevice Device;
private readonly ViewManagement viewManagement;
@@ -51,81 +49,6 @@ namespace Net462DllTest.ViewModel
this.plcVarModelDataProxy = plcVarModelDataProxy;
InitCommand(); // 初始化指令
webSocketServer.MsgHandleHelper.AddModule(this); // 用于关闭窗体时移除监听
CommandCloseForm = new RelayCommand((p) =>
{
webSocketServer.MsgHandleHelper.RemoteModule(this); // 用于关闭窗体时移除监听
});
//Console.WriteLine($"Emit {sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
//var msgHandl = new WsMsgHandl<LibSpace>()
//{
// DataJsonKey = "data", // 数据键
// ThemeJsonKey = "theme", // 主题键
//};
//msgHandl.AddHandle<LibSpace>(nameof(GetSpace), GetSpace); // theme:AddUser
//msgHandl.AddHandle<LibSpace>(nameof(UpData), UpData); // theme:DeleteUser
//webSocketServer.AddModule(msgHandl);
//CommandCloseForm = new RelayCommand((p) =>
//{
// webSocketServer.RemoteModule(msgHandl); // 用于关闭窗体时移除监听
//});
}
Action<string> Recover;
[AutoSocketHandle(ThemeValue = "SavaRecover")]
public async Task SavaRecover(int waitTime , Action<string> Recover)
{
if(waitTime <=0 || waitTime>= 10000)
{
return;
}
await Task.Delay(waitTime);
Recover("haha~" );
this.Recover = Recover;
return;
}
[AutoSocketHandle(ThemeValue = "Invoke")]
public void Invoke(string a)
{
if (Recover is null)
return;
Recover("haha~"+a);
}
[AutoSocketHandle(ThemeValue = "PlcModel")]
public async Task<PlcVarModelDataProxy> GetModelData(Action<object> Recover)
{
Recover("等待5秒");
await Task.Delay(5000);
//Recover.Invoke(plcVarModelDataProxy);
return plcVarModelDataProxy;
}
[AutoSocketHandle(ThemeValue = "Up")]
public void UpData(LibSpace libSpace, Action<dynamic> Recover)
{
Recover("收到");
return;
}
[AutoSocketHandle(ThemeValue = "Bind")]
public LibSpace SpaceBind(string spaceNum, string plateNumber, Action<string> Recover)
{
return new LibSpace
{
PlateNumber = plateNumber,
SpaceNum = spaceNum,
};
}

View File

@@ -36,7 +36,7 @@ namespace Net462DllTest.Web
* "value":0,
* }
*/
[WebApi(API.POST)]
[WebApi(ApiType.POST)]
public dynamic PlcOp([Url] string var, int value)
{
if (EnumHelper.TryConvertEnum<PlcVarName>(var,out var signal))
@@ -61,7 +61,7 @@ namespace Net462DllTest.Web
* "value":0,
* }
*/
[WebApi(API.POST)]
[WebApi(ApiType.POST)]
public dynamic Trigger([Url] string command, int value)
{
if (EnumHelper.TryConvertEnum<CommandSignal>(command, out var signal))

View File

@@ -0,0 +1,170 @@
using IoTClient.Common.Enums;
using Net462DllTest.Enums;
using Net462DllTest.Model;
using Net462DllTest.Trigger;
using Serein.Library.Api;
using Serein.Library.Attributes;
using Serein.Library.Enums;
using Serein.Library.Ex;
using Serein.Library.Framework.NodeFlow;
using Serein.Library.Network.WebSocketCommunication;
using Serein.Library.NodeFlow.Tool;
using Serein.Library.Web;
using System;
using System.Threading.Tasks;
namespace Net462DllTest.Web
{
[DynamicFlow("[PlcSocketService]")]
[AutoRegister]
[AutoSocketModule(JsonThemeField = "theme", JsonDataField = "data")]
public class PlcSocketService : ISocketControlBase
{
public Guid HandleGuid { get; } = new Guid();
private readonly SiemensPlcDevice MyPlc;
private readonly PlcVarModelDataProxy plcVarModelDataProxy;
public PlcSocketService(SiemensPlcDevice MyPlc,
PlcVarModelDataProxy plcVarModelDataProxy)
{
this.MyPlc = MyPlc;
this.plcVarModelDataProxy = plcVarModelDataProxy;
}
#region 退
[NodeAction(NodeType.Init)]
public void Init(IDynamicContext context)
{
context.Env.IOC.Register<WebSocketServer>();
context.Env.IOC.Register<WebSocketClient>();
context.Env.IOC.Register<IRouter, Router>();
context.Env.IOC.Register<WebApiServer>();
}
[NodeAction(NodeType.Loading)] // Loading 初始化完成已注入依赖项,可以开始逻辑上的操作
public void Loading(IDynamicContext context)
{
// 注册控制器
context.Env.IOC.Run<IRouter, WebApiServer>((router, apiServer) => {
router.AddHandle(typeof(FlowController));
apiServer.Start("http://*:8089/"); // 开启 Web Api 服务
});
context.Env.IOC.Run<WebSocketServer>(async (socketServer) => {
socketServer.MsgHandleHelper.AddModule(this, (ex, recover) =>
{
recover(new
{
ex = ex.Message,
storehouseInfo = ex.StackTrace
});
});
await socketServer.StartAsync("http://localhost:5005/"); // 开启 Web Socket 监听
});
context.Env.IOC.Run<WebSocketClient>(async client => {
await client.ConnectAsync("ws://localhost:5005/"); // 连接到服务器
});
}
[NodeAction(NodeType.Exit)] // 流程结束时自动执行
public void Exit(IDynamicContext context)
{
context.Env.IOC.Run<WebApiServer>((apiServer) =>
{
apiServer?.Stop(); // 关闭 Web 服务
});
context.Env.IOC.Run<WebSocketServer>((socketServer) =>
{
socketServer?.Stop(); // 关闭 Web 服务
});
MyPlc.Close();
MyPlc.CancelAllTasks();
}
#endregion
[NodeAction(NodeType.Action, "等待")]
public async Task Delay(int ms = 5000)
{
await Console.Out.WriteLineAsync("开始等待");
await Task.Delay(ms);
await Console.Out.WriteLineAsync("不再等待");
}
[AutoSocketHandle(IsReturnValue = false)]
public SiemensPlcDevice PlcInit(SiemensVersion version = SiemensVersion.None,
string ip = "192.168.10.100",
int port = 102)
{
MyPlc.Model.Set(PlcVarName.DoorVar, (Int16)1);
MyPlc.Model.Get(PlcVarName.DoorVar);
if (MyPlc.Client is null)
{
try
{
MyPlc.Init(version, ip, port);
Console.WriteLine($"西门子PLC初始化成功[{version},{ip}:{port}]");
}
catch (Exception ex)
{
Console.WriteLine($"西门子PLC[{version},{ip}:{port}]初始化异常:{ex.Message}");
}
}
else
{
Console.WriteLine($"西门子PLC已经初始化[{version},{ip}:{port}]");
}
return MyPlc;
}
[AutoSocketHandle(IsReturnValue = false)]
public SiemensPlcDevice SetState(PlcState state = PlcState.PowerOff)
{
var oldState = MyPlc.State;
MyPlc.State = state;
Console.WriteLine($"PLC状态从[{oldState}]转为[{state}]");
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)
{
MyPlc.Write(varName, value); // 新数据
return MyPlc;
}
public PlcVarModelDataProxy BatchReadVar()
{
MyPlc.BatchRefresh();
return plcVarModelDataProxy;
}
public void OpenTimedRefresh()
{
Task.Run(async () => await MyPlc.OpenTimedRefreshAsync());
}
public void CloseTimedRefresh()
{
MyPlc.CloseTimedRefresh();
}
}
}

View File

@@ -1,15 +0,0 @@
using Net462DllTest.ViewModel;
using Serein.Library.Attributes;
using Serein.Library.Network.WebSocketCommunication;
using Serein.Library.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Net462DllTest.Web
{
}