diff --git a/.gitignore b/.gitignore index 5c3a4ae..76834ab 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ *.user *.suo +# 排除 Rider 相关文件夹 +.idea + # 排除编译输出文件夹 bin/ obj/ @@ -18,11 +21,14 @@ obj/ *.exe # 排除发布文件夹 + .Output/ /.git1 + doc WorkBench.ControlLibrary.Core WorkBench.Remote Serein.FlowStartTool Serein.CloudWorkbench Serein.CollaborationSync +Serein.Workbench.Avalonia diff --git a/Library/Utils/JsonHelper.cs b/Library/Utils/JsonHelper.cs index c02bf1f..1123512 100644 --- a/Library/Utils/JsonHelper.cs +++ b/Library/Utils/JsonHelper.cs @@ -12,7 +12,7 @@ namespace Serein.Library.Utils /// /// Json门户类,需要你提供实现 /// - private static IJsonProvider provider; + public static IJsonProvider Provider { get; private set; } /// /// 使用第三方包进行解析 @@ -20,7 +20,7 @@ namespace Serein.Library.Utils /// public static void UseJsonProvider(IJsonProvider jsonPortal) { - JsonHelper.provider = jsonPortal; + JsonHelper.Provider = jsonPortal; } /// @@ -32,7 +32,7 @@ namespace Serein.Library.Utils public static T Deserialize(string jsonText) { - return provider.Deserialize(jsonText); + return Provider.Deserialize(jsonText); } /// @@ -43,7 +43,7 @@ namespace Serein.Library.Utils /// public static object Deserialize(string jsonText, Type type) { - return provider.Deserialize(jsonText, type); + return Provider.Deserialize(jsonText, type); } @@ -55,7 +55,7 @@ namespace Serein.Library.Utils public static IJsonToken Parse(string json) { - return provider.Parse(json); + return Provider.Parse(json); } /// @@ -66,7 +66,7 @@ namespace Serein.Library.Utils /// public static bool TryParse(string json, out IJsonToken jsonToken) { - return provider.TryParse(json, out jsonToken); + return Provider.TryParse(json, out jsonToken); } @@ -78,7 +78,7 @@ namespace Serein.Library.Utils /// public static string Serialize(object obj) { - return provider.Serialize(obj); + return Provider.Serialize(obj); } /// @@ -90,7 +90,7 @@ namespace Serein.Library.Utils { var dict = new Dictionary(); init(dict); - return provider.CreateObject(dict); + return Provider.CreateObject(dict); } /// @@ -100,7 +100,7 @@ namespace Serein.Library.Utils /// public static IJsonToken Array(IEnumerable values) { - return provider.CreateArray(values); + return Provider.CreateArray(values); } /// @@ -111,8 +111,8 @@ namespace Serein.Library.Utils public static IJsonToken FromObject(object obj) { if (obj is System.Collections.IEnumerable && !(obj is string)) - return provider.CreateObject(obj as IDictionary); - return provider.CreateArray(obj as IEnumerable); + return Provider.CreateObject(obj as IDictionary); + return Provider.CreateArray(obj as IEnumerable); } } diff --git a/Library/Utils/SereinIoc.cs b/Library/Utils/SereinIoc.cs index 92629ca..a663a0e 100644 --- a/Library/Utils/SereinIoc.cs +++ b/Library/Utils/SereinIoc.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Reflection; @@ -9,7 +10,18 @@ using System.Text; namespace Serein.Library.Utils { - + /// + /// 指示IOC扫描构造函数时的行为 + /// + [AttributeUsage(AttributeTargets.Constructor)] + public sealed class SereinIOCCtorAttribute : Attribute + { + /// + /// 忽略该构造函数 + /// + public bool IsIgnore = false; + } + /// /// 一个轻量级的单例IOC容器 /// @@ -380,7 +392,19 @@ namespace Serein.Library.Utils /// private ConstructorInfo[] GetConstructor(Type type) { - return type.GetConstructors().OrderByDescending(ctor => ctor.GetParameters().Length).ToArray(); + return type.GetConstructors().Where(ctor => + { + var attribute = ctor.GetCustomAttribute(); + if (attribute is null) + { + return true; + } + else + { + return !attribute.IsIgnore; + } + }) + .OrderByDescending(ctor => ctor.GetParameters().Length).ToArray(); } /// @@ -556,6 +580,11 @@ namespace Serein.Library.Utils if (typeName.Equals("Serein.Library.LightweightFlowEnvironment")) { + } + + if (_registerCallback.TryGetValue(typeName, out var registerCallback)) + { + } if (_dependencies.ContainsKey(typeName)) { diff --git a/Library/Utils/UIContextOperation.cs b/Library/Utils/UIContextOperation.cs index 25a204d..f8ce70e 100644 --- a/Library/Utils/UIContextOperation.cs +++ b/Library/Utils/UIContextOperation.cs @@ -34,11 +34,15 @@ namespace Serein.Library.Utils } } + + + /// /// 传入UI线程上下文 /// /// 线程上下文 + [SereinIOCCtor(IsIgnore = true)] public UIContextOperation(SynchronizationContext synchronizationContext) { this.context = synchronizationContext; @@ -48,6 +52,7 @@ namespace Serein.Library.Utils /// 传入获取UI线程上下文的闭包创建 /// /// 获取线程上下文的闭包函数 + [SereinIOCCtor(IsIgnore = true)] public UIContextOperation(Func getUiContext) { this.getUiContext = getUiContext; diff --git a/NodeFlow/Env/FlowControl.cs b/NodeFlow/Env/FlowControl.cs index 9a374f5..4f561f1 100644 --- a/NodeFlow/Env/FlowControl.cs +++ b/NodeFlow/Env/FlowControl.cs @@ -24,21 +24,21 @@ namespace Serein.NodeFlow.Env private readonly FlowLibraryService flowLibraryService; private readonly FlowOperationService flowOperationService; private readonly FlowModelService flowModelService; - private readonly UIContextOperation UIContextOperation; + private readonly UIContextOperation uiContextOperation; public FlowControl(IFlowEnvironment flowEnvironment, IFlowEnvironmentEvent flowEnvironmentEvent, FlowLibraryService flowLibraryService, FlowOperationService flowOperationService, FlowModelService flowModelService, - UIContextOperation UIContextOperation) + UIContextOperation uiContextOperation) { this.flowEnvironment = flowEnvironment; this.flowEnvironmentEvent = flowEnvironmentEvent; this.flowLibraryService = flowLibraryService; this.flowOperationService = flowOperationService; this.flowModelService = flowModelService; - this.UIContextOperation = UIContextOperation; + this.uiContextOperation = uiContextOperation; contexts = new ObjectPool(() => new FlowContext(flowEnvironment), context => context.Reset()); flowTaskOptions = new FlowWorkOptions @@ -340,7 +340,7 @@ namespace Serein.NodeFlow.Env { flowWorkManagement.Exit(); } - UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnFlowRunComplete(new FlowEventArgs())); + uiContextOperation?.Invoke(() => flowEnvironmentEvent.OnFlowRunComplete(new FlowEventArgs())); IOC.Reset(); GC.Collect(); return Task.FromResult(true); diff --git a/NodeFlow/Env/FlowEnvironment.cs b/NodeFlow/Env/FlowEnvironment.cs index 07c3bf1..92298ad 100644 --- a/NodeFlow/Env/FlowEnvironment.cs +++ b/NodeFlow/Env/FlowEnvironment.cs @@ -63,7 +63,44 @@ namespace Serein.NodeFlow.Env .Build(); // 设置JSON解析器 - JsonHelper.UseJsonProvider(new NewtonsoftJsonProvider()); + if (JsonHelper.Provider is null) + { + JsonHelper.UseJsonProvider(new NewtonsoftJsonProvider()); + } + + // 默认使用本地环境 + currentFlowEnvironment = ioc.Get(); + currentFlowEnvironmentEvent = ioc.Get(); + SereinEnv.SetEnv(currentFlowEnvironment); + } + + /// + /// 提供上下文操作进行调用 + /// + /// + public FlowEnvironment(UIContextOperation operation) + { + ISereinIOC ioc = new SereinIOC(); + ioc.Register(()=> ioc) // IOC容器接口 + .Register(() => operation) // 流程环境接口 + .Register(() => this) // 流程环境接口 + .Register() // 流程环境事件接口 + .Register() // 流程编辑接口 + .Register() // 流程控制接口 + .Register() // 本地环境 + .Register() // 节点/画布模型服务 + .Register() // 流程库服务 + .Register() // 代码生成 + .Register() // 流程操作 + .Register() // 节点MVVM服务 + .Build(); + + // 设置JSON解析器 + if (JsonHelper.Provider is null) + { + JsonHelper.UseJsonProvider(new NewtonsoftJsonProvider()); + } + // 默认使用本地环境 currentFlowEnvironment = ioc.Get(); currentFlowEnvironmentEvent = ioc.Get(); diff --git a/NodeFlow/Env/LocalFlowEnvironment.cs b/NodeFlow/Env/LocalFlowEnvironment.cs index 7577f4f..00076b9 100644 --- a/NodeFlow/Env/LocalFlowEnvironment.cs +++ b/NodeFlow/Env/LocalFlowEnvironment.cs @@ -245,12 +245,14 @@ namespace Serein.NodeFlow.Env /// public void LoadProject(string filePath) { - string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容 + _ = Task.Run(async () => + { + await this.LoadProjetAsync((filePath)); + }); + /*string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容 var FlowProjectData = JsonHelper.Deserialize(content); var FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;// - - this.ProjectFileLocation = filePath; var projectData = FlowProjectData; @@ -285,30 +287,50 @@ namespace Serein.NodeFlow.Env } Event.OnProjectLoaded(new ProjectLoadedEventArgs()); - }); + });*/ } + public async Task LoadProjetAsync(string filePath) { - string content = await System.IO.File.ReadAllTextAsync(filePath); // 读取整个文件内容 - var FlowProjectData = JsonHelper.Deserialize(content); - var FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;// - if(FlowProjectData is null) + var content = await System.IO.File.ReadAllTextAsync(filePath); // 读取整个文件内容 + var flowProjectData = JsonHelper.Deserialize(content); + var fileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;// + if(flowProjectData is null) { return; } + var projectData = flowProjectData ?? throw new ArgumentNullException(nameof(flowProjectData)); + if (!_flowLibraryService.IsLoadedBaseLibrary) + { + var baseLibrary = _flowLibraryService.LoadBaseLibrary(); + if (baseLibrary.MethodInfos.Count > 0 && UIContextOperation is not null) + { + await UIContextOperation.InvokeAsync(() => Event.OnDllLoad(new LoadDllEventArgs(baseLibrary))); // 通知UI创建dll面板显示 + } + + if (_flowModelService.GetAllCanvasModel().Count == 0) + { + // 创建第一个画布 + FlowEdit.CreateCanvas("Default", 1920, 1080); + } + + } + + + + + this.ProjectFileLocation = filePath; - var projectData = FlowProjectData; // 加载项目配置文件 var dllPaths = projectData.Librarys.Select(it => it.FilePath).ToList(); - List methodDetailss = []; // 遍历依赖项中的特性注解,生成方法详情 foreach (var dllPath in dllPaths) { - string cleanedRelativePath = dllPath.TrimStart('.', '\\'); + var cleanedRelativePath = dllPath.TrimStart('.', '\\'); var tmpPath = Path.Combine(filePath, cleanedRelativePath); var dllFilePath = Path.GetFullPath(tmpPath); LoadLibrary(dllFilePath); // 加载项目文件时加载对应的程序集 @@ -526,7 +548,8 @@ namespace Serein.NodeFlow.Env return; } this.UIContextOperation = uiContextOperation; - IOC.Register(() => uiContextOperation).Build(); + IOC.Register(() => uiContextOperation); + IOC.Build(); OnUIContextOperationSet(); } @@ -656,18 +679,11 @@ namespace Serein.NodeFlow.Env #endregion /// - /// 设置了 UIContextOperation 需要立刻执行的方法,用于加载基础库,创建第一个画布。 + /// 设置了 UIContextOperation 需要立刻执行的方法 /// 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); + } } diff --git a/NodeFlow/Model/Librarys/FlowLibraryCache.cs b/NodeFlow/Model/Librarys/FlowLibraryCache.cs index 3d7da56..b4e3c97 100644 --- a/NodeFlow/Model/Librarys/FlowLibraryCache.cs +++ b/NodeFlow/Model/Librarys/FlowLibraryCache.cs @@ -1,5 +1,6 @@ using Serein.Library; using Serein.NodeFlow.Tool; +using System.Globalization; using System.Reflection; namespace Serein.NodeFlow.Model.Library @@ -229,14 +230,17 @@ namespace Serein.NodeFlow.Model.Library 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)); + var mdInfos = MethodDetailss.Values.Select(x => x.ToInfo()) + .OrderBy(d => d.AssemblyName) + .ThenBy(s => s.MethodAnotherName, StringComparer.Create(CultureInfo.GetCultureInfo("zh-cn"), true)) + .ToList(); + return new FlowLibraryInfo { AssemblyName = assemblyName, FileName = FullName, FilePath = FilePath, - MethodInfos = mdInfos.ToList(), + MethodInfos = mdInfos, }; } diff --git a/NodeFlow/Services/FlowLibraryService.cs b/NodeFlow/Services/FlowLibraryService.cs index 02b1360..dbc756e 100644 --- a/NodeFlow/Services/FlowLibraryService.cs +++ b/NodeFlow/Services/FlowLibraryService.cs @@ -14,6 +14,11 @@ namespace Serein.NodeFlow.Services /// public class FlowLibraryService { + /// + /// 是否加载过基础依赖 + /// + public bool IsLoadedBaseLibrary { get; private set; } = false; + /// /// 构造函数,初始化流程依赖 /// @@ -60,7 +65,7 @@ namespace Serein.NodeFlow.Services /// public FlowLibraryInfo LoadBaseLibrary() { - Assembly baseAssmbly = typeof(FlowBaseLibrary).Assembly; + var baseAssmbly = typeof(FlowBaseLibrary).Assembly; var flowLibrary = new FlowLibraryCache(baseAssmbly); flowLibrary.LoadFlowMethod(); var assemblyName = baseAssmbly.GetName().Name; @@ -69,7 +74,9 @@ namespace Serein.NodeFlow.Services throw new Exception($"程序集\"{baseAssmbly}\"返回 Name 为 null"); } _flowLibraryCaches.TryAdd(assemblyName, flowLibrary); - return flowLibrary.ToInfo(); + var infos = flowLibrary.ToInfo(); + IsLoadedBaseLibrary = true; + return infos; } /// diff --git a/NodeFlow/Tool/NodeMethodDetailsHelper.cs b/NodeFlow/Tool/NodeMethodDetailsHelper.cs index b0450f7..fc616a6 100644 --- a/NodeFlow/Tool/NodeMethodDetailsHelper.cs +++ b/NodeFlow/Tool/NodeMethodDetailsHelper.cs @@ -332,7 +332,7 @@ public static class NodeMethodDetailsHelper { isExplicitData = nodeParmsAttribute.IsExplicit; // 设置是否是显式参数 } - if (string.IsNullOrEmpty(nodeParmsAttribute.Name)) + if (!string.IsNullOrEmpty(nodeParmsAttribute.Name)) { description = nodeParmsAttribute.Name; // 设置显示的名称 } diff --git a/README.md b/README.md index d4ee366..4b41ea0 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,10 @@ This project supports both **English** and **中文** documentation. ## 🔗 External Links -- Bilibili: https://space.bilibili.com/33526379 \ No newline at end of file +- Bilibili: https://space.bilibili.com/33526379 + +# 社群 + +QQ群 955830545 +提供技术交流与支持,欢迎加入。 +因为个人是社畜,所以可能不会及时回复,请谅解。 \ No newline at end of file diff --git a/Serein.Proto.HttpApi/ApiHandleConfig.cs b/Serein.Proto.HttpApi/ApiHandleConfig.cs index bfe3adb..5c4a815 100644 --- a/Serein.Proto.HttpApi/ApiHandleConfig.cs +++ b/Serein.Proto.HttpApi/ApiHandleConfig.cs @@ -154,7 +154,15 @@ namespace Serein.Proto.HttpApi } else if (jsonObject != null && PostArgTypes[i] == PostArgType.IsBobyData) { - args[i] = jsonObject.ToObject(type); + if (type.IsEnum) + { + args[i] = jsonObject.ToObject(type); + } + + else + { + args[i] = jsonObject.ToObject(type); + } } else if (jsonObject != null) { diff --git a/Serein.Proto.HttpApi/HandleState.cs b/Serein.Proto.HttpApi/HandleState.cs new file mode 100644 index 0000000..350e8fc --- /dev/null +++ b/Serein.Proto.HttpApi/HandleState.cs @@ -0,0 +1,54 @@ +namespace Serein.Proto.HttpApi +{ + public enum HandleState + { + /// + /// 默认值 + /// + None , + + /// + /// 没有异常 + /// + Ok, + + /// + /// 没有对应的控制器 + /// + NotHanleController, + + /// + /// 没有对应的Http请求类型 + /// + NotHttpApiRequestType, + + /// + /// 没有处理配置 + /// + NotHandleConfig, + + /// + /// 无法实例化控制器 + /// + HanleControllerIsNull, + + /// + /// 调用参数获取错误 + /// + InvokeArgError, + + /// + /// 调用发生异常 + /// + InvokeErrored, + + /// + /// 请求被阻止 + /// + RequestBlocked, + } + + + +} + diff --git a/Serein.Proto.HttpApi/InvokeResult.cs b/Serein.Proto.HttpApi/InvokeResult.cs new file mode 100644 index 0000000..1143f73 --- /dev/null +++ b/Serein.Proto.HttpApi/InvokeResult.cs @@ -0,0 +1,56 @@ +namespace Serein.Proto.HttpApi +{ + /// + /// 调用结果 + /// + public class InvokeResult + { + /// + /// 处理工具记录的请求Id,用于匹配请求与响应 + /// + public long RequestId { get; set; } + /// + /// 调用状态 + /// + public HandleState State { get; set; } + /// + /// 调用正常时这里会有数据 + /// + public object? Data{ get; set; } + /// + /// 调用失败时这里可能会有异常数据 + /// + public Exception? Exception { get; set; } + + /// + /// 调用成功 + /// + /// + /// + /// + public static InvokeResult Ok(long requestId, object? data) => new InvokeResult + { + RequestId = requestId, + Data = data, + State = HandleState.Ok, + }; + + /// + /// 调用失败 + /// + /// + /// + /// + /// + public static InvokeResult Fail(long requestId, HandleState state, Exception? ex = null) => new InvokeResult + { + RequestId = requestId, + State = state, + Exception = ex, + }; + } + + + +} + diff --git a/Serein.Proto.HttpApi/PathRouter.cs b/Serein.Proto.HttpApi/PathRouter.cs index 5838557..72fc6bf 100644 --- a/Serein.Proto.HttpApi/PathRouter.cs +++ b/Serein.Proto.HttpApi/PathRouter.cs @@ -17,140 +17,18 @@ using Type = System.Type; namespace Serein.Proto.HttpApi { - /// - /// 路由接口 - /// - public interface IPathRouter - { - /// - /// 添加处理模块 - /// - /// - void AddHandle(Type controllerType); - /// - /// 获取路由信息 - /// - /// - List GetRouterInfos(); - - /// - /// 路由解析开始处理 - /// - /// - /// - Task HandleAsync(HttpListenerContext context); - } - - - public enum HandleState - { - /// - /// 默认值 - /// - None , - /// - /// 没有异常 - /// - Ok, - /// - /// 没有对应的控制器 - /// - NotHanleController, - /// - /// 没有对应的Http请求类型 - /// - NotHttpApiRequestType, - /// - /// 没有处理配置 - /// - NotHandleConfig, - /// - /// 无法实例化控制器 - /// - HanleControllerIsNull, - - /// - /// 调用参数获取错误 - /// - InvokeArgError, - - /// - /// 调用发生异常 - /// - InvokeErrored, - } - - /// - /// 调用结果 - /// - public class InvokeResult - { - /// - /// 调用状态 - /// - public HandleState State { get; set; } - /// - /// 调用正常时这里会有数据 - /// - public object? Data{ get; set; } - /// - /// 调用失败时这里可能会有异常数据 - /// - public Exception? Exception { get; set; } - - public static InvokeResult Ok(object? data) => new InvokeResult - { - Data = data, - State = HandleState.Ok, - }; - public static InvokeResult Fail(HandleState state, Exception? ex = null) => new InvokeResult - { - State = state, - Exception = ex, - }; - } - - /// - /// 路由信息 - /// - public class RouterInfo - { -#if NET6_0_OR_GREATER - /// - /// 接口类型 - /// - public ApiType ApiType { get; set; } - /// - /// 接口URL - /// - public required string Url { get; set; } - /// - /// 对应的处理方法 - /// - public required MethodInfo MethodInfo { get; set; } -#else - /// - /// 接口类型 - /// - public ApiType ApiType { get; set; } - /// - /// 接口URL - /// - public string Url { get; set; } - /// - /// 对应的处理方法 - /// - public MethodInfo MethodInfo { get; set; } -#endif - } - - + /// /// 路由注册与解析 /// - public class PathRouter : IPathRouter + internal class PathRouter { - private readonly ISereinIOC SereinIOC; // 用于存储路由信息 + /// + /// IOC容器 + /// + private readonly ISereinIOC SereinIOC; + + private long _requestId = 0; /// /// 控制器实例对象的类型,每次调用都会重新实例化,[Url - ControllerType] @@ -162,6 +40,12 @@ namespace Serein.Proto.HttpApi /// private readonly ConcurrentDictionary> HandleModels = new ConcurrentDictionary>(); + /// + /// 请求时的处理函数,传入API类型、URL、Body + /// + internal Func? OnBeforRequest; + + public PathRouter(ISereinIOC SereinIOC) { this.SereinIOC = SereinIOC; @@ -238,19 +122,35 @@ namespace Serein.Proto.HttpApi public async Task HandleAsync(HttpListenerContext context) { var request = context.Request; // 获取请求对象 + var uri = request.Url; // 获取请求的完整URL var httpMethod = request.HttpMethod.ToUpper(); // 获取请求的 HTTP 方法 + var fullUrl = uri.ToString(); // 获取完整URL字符串 + var routeValues = GetUrlData(fullUrl); // 解析 URL 获取路由参数 + var requestBody = await ReadRequestBodyAsync(request); // 读取请求体内容 + var requestId = System.Threading.Interlocked.Increment(ref _requestId); + var requestInfo = new ApiRequestInfo + { + RequestId = requestId, + ApiType = httpMethod, + Url = fullUrl, + Body = requestBody, + }; + if (OnBeforRequest?.Invoke(requestInfo) == false) + { + return InvokeResult.Fail(requestId, HandleState.RequestBlocked); // 请求被阻止 + } if (!HandleModels.TryGetValue(httpMethod, out var modules) || request.Url is null) { - return InvokeResult.Fail(HandleState.NotHttpApiRequestType); // 没有对应HTTP请求方法的处理 + return InvokeResult.Fail(requestId, HandleState.NotHttpApiRequestType); // 没有对应HTTP请求方法的处理 } var template = request.Url.AbsolutePath.ToLower() ; if (!_controllerTypes.TryGetValue(template, out var controllerType)) { - return InvokeResult.Fail(HandleState.NotHanleController); // 没有对应的处理器 + return InvokeResult.Fail(requestId, HandleState.NotHanleController); // 没有对应的处理器 } if (!modules.TryGetValue(template, out var config)) { - return InvokeResult.Fail(HandleState.NotHandleConfig); // 没有对应的处理配置 + return InvokeResult.Fail(requestId, HandleState.NotHandleConfig); // 没有对应的处理配置 } ControllerBase controllerInstance; @@ -260,13 +160,13 @@ namespace Serein.Proto.HttpApi } catch { - return InvokeResult.Fail(HandleState.HanleControllerIsNull); // 未找到控制器实例 + return InvokeResult.Fail(requestId, HandleState.HanleControllerIsNull); // 未找到控制器实例 } - var url = request.Url; // 获取请求的完整URL - var routeValues = GetUrlData(url); // 解析 URL 获取路由参数 - controllerInstance.Url = url.AbsolutePath; + + + controllerInstance.Url = uri.AbsolutePath; // 设置控制器实例的 URL 属性 object?[] args; switch (httpMethod) @@ -275,32 +175,32 @@ namespace Serein.Proto.HttpApi args = config.GetArgsOfGet(routeValues); // Get请求 break; case "POST": - var requestBody = await ReadRequestBodyAsync(request); // 读取请求体内容 controllerInstance.Body = requestBody; if (!JsonHelper.TryParse(requestBody, out var requestJObject)) { var exTips = $"body 无法转换为 json 数据, body: {requestBody}"; - return InvokeResult.Fail(HandleState.InvokeArgError, new Exception(exTips)); + return InvokeResult.Fail(requestId, HandleState.InvokeArgError, new Exception(exTips)); } (var isPass, var index, var type, var ex) = config.TryGetArgsOfPost(routeValues, requestJObject, out args); if (!isPass) { var exTips = $"尝试转换第{index}个入参参数时,类型 {type.FullName} 参数获取失败:{ex?.Message}"; - return InvokeResult.Fail(HandleState.InvokeArgError, new Exception(exTips)); + return InvokeResult.Fail(requestId, HandleState.InvokeArgError, new Exception(exTips)); } break; default: - return InvokeResult.Fail(HandleState.NotHttpApiRequestType); + return InvokeResult.Fail(requestId, HandleState.NotHttpApiRequestType); } + try { var invokeResult = await config.HandleAsync(controllerInstance, args); - return InvokeResult.Ok(invokeResult); + return InvokeResult.Ok(requestId, invokeResult); } catch (Exception ex) { - return InvokeResult.Fail(HandleState.InvokeErrored, ex); + return InvokeResult.Fail(requestId, HandleState.InvokeErrored, ex); } } @@ -403,11 +303,11 @@ namespace Serein.Proto.HttpApi /// /// /// - private Dictionary GetUrlData(Uri uri) + private Dictionary GetUrlData(string uri) { Dictionary routeValues = new Dictionary(); - var pathParts = uri.ToString().Split('?'); // 拆分 URL,获取路径部分 + var pathParts = uri.Split('?'); // 拆分 URL,获取路径部分 if (pathParts.Length > 1) // 如果包含查询字符串 { diff --git a/Serein.Proto.HttpApi/RouterInfo.cs b/Serein.Proto.HttpApi/RouterInfo.cs new file mode 100644 index 0000000..a6a8411 --- /dev/null +++ b/Serein.Proto.HttpApi/RouterInfo.cs @@ -0,0 +1,42 @@ +using System.Reflection; + +namespace Serein.Proto.HttpApi +{ + /// + /// 路由信息 + /// + public class RouterInfo + { +#if NET6_0_OR_GREATER + /// + /// 接口类型 + /// + public ApiType ApiType { get; set; } + /// + /// 接口URL + /// + public required string Url { get; set; } + /// + /// 对应的处理方法 + /// + public required MethodInfo MethodInfo { get; set; } +#else + /// + /// 接口类型 + /// + public ApiType ApiType { get; set; } + /// + /// 接口URL + /// + public string Url { get; set; } + /// + /// 对应的处理方法 + /// + public MethodInfo MethodInfo { get; set; } +#endif + } + + + +} + diff --git a/Serein.Proto.HttpApi/Serein.Proto.HttpApi.csproj b/Serein.Proto.HttpApi/Serein.Proto.HttpApi.csproj index 3959e18..7019f40 100644 --- a/Serein.Proto.HttpApi/Serein.Proto.HttpApi.csproj +++ b/Serein.Proto.HttpApi/Serein.Proto.HttpApi.csproj @@ -8,7 +8,7 @@ ..\.\.Output 基于Json数据载体的HttpApi交互工具包 - 0.0.9 + 0.0.11 基于Json数据载体的HttpApi交互工具包 MIT True diff --git a/Serein.Proto.HttpApi/SereinWebApiService.cs b/Serein.Proto.HttpApi/SereinWebApiService.cs index aeddd33..e7bd8e7 100644 --- a/Serein.Proto.HttpApi/SereinWebApiService.cs +++ b/Serein.Proto.HttpApi/SereinWebApiService.cs @@ -1,26 +1,27 @@ using Serein.Library; +using Serein.Library.Api; using Serein.Library.Utils; using System.Net; using System.Text; namespace Serein.Proto.HttpApi { - + /// /// 对于 HttpListenerContext 的拓展服务 /// public class SereinWebApiService { - private readonly IPathRouter _pathRouter; + private readonly PathRouter _pathRouter; //private RequestLimiter? requestLimiter; /// /// 初始化处理器 /// /// - public SereinWebApiService(IPathRouter pathRouter) + public SereinWebApiService(ISereinIOC sereinIOC) { - _pathRouter = pathRouter; + _pathRouter = new PathRouter(sereinIOC); } /// @@ -50,7 +51,10 @@ namespace Serein.Proto.HttpApi return _pathRouter.GetRouterInfos(); } - private Func OnBeforeReplying; + /// + /// 传入方法调用结果,返回最终回复的内容和状态码 + /// + private Func? OnBeforeReplying; /// /// 设置回复前的处理函数 @@ -61,6 +65,16 @@ namespace Serein.Proto.HttpApi OnBeforeReplying = func; } + /// + /// 请求时的处理函数,传入API类型、URL、Body + /// + /// + public void SetOnBeforeRequest(Func func) + { + _pathRouter.OnBeforRequest = func; + } + + /// /// 处理请求 /// @@ -118,4 +132,30 @@ namespace Serein.Proto.HttpApi } } + + /// + /// 外部请求的信息 + /// + public class ApiRequestInfo + { + /// + /// 请求编号 + /// + public long RequestId { get; set; } + + /// + /// API类型 GET/POST + /// + public string ApiType { get; set; } + + /// + /// 请求的URL + /// + public string Url { get; set; } + + /// + /// 请求的Body + /// + public string? Body { get; set; } + } } diff --git a/SereinFlow.sln b/SereinFlow.sln index 8e92a96..180c0be 100644 --- a/SereinFlow.sln +++ b/SereinFlow.sln @@ -30,6 +30,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serein.Proto.Modbus", "Sere EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serein.Proto.HttpApi", "Serein.Proto.HttpApi\Serein.Proto.HttpApi.csproj", "{281B8E55-B9CD-4FE5-A72F-59CBB968D844}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serein.Workbench.Avalonia", "Serein.Workbench.Avalonia\Serein.Workbench.Avalonia.csproj", "{3115002B-4CDA-4793-803A-5C1BA95EC6C5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -80,6 +82,10 @@ Global {281B8E55-B9CD-4FE5-A72F-59CBB968D844}.Debug|Any CPU.Build.0 = Debug|Any CPU {281B8E55-B9CD-4FE5-A72F-59CBB968D844}.Release|Any CPU.ActiveCfg = Release|Any CPU {281B8E55-B9CD-4FE5-A72F-59CBB968D844}.Release|Any CPU.Build.0 = Release|Any CPU + {3115002B-4CDA-4793-803A-5C1BA95EC6C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3115002B-4CDA-4793-803A-5C1BA95EC6C5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3115002B-4CDA-4793-803A-5C1BA95EC6C5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3115002B-4CDA-4793-803A-5C1BA95EC6C5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Workbench/Serein.WorkBench.csproj b/Workbench/Serein.WorkBench.csproj index 21e22fc..6a3ab67 100644 --- a/Workbench/Serein.WorkBench.csproj +++ b/Workbench/Serein.WorkBench.csproj @@ -81,7 +81,7 @@ - + diff --git a/Workbench/Services/KeyEventService.cs b/Workbench/Services/KeyEventService.cs index 8540b53..a7efdbf 100644 --- a/Workbench/Services/KeyEventService.cs +++ b/Workbench/Services/KeyEventService.cs @@ -55,7 +55,6 @@ namespace Serein.Workbench.Services /// /// void KeyUp(Key key); - } ///