mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-05-01 03:53:22 +08:00
内置了Web Server/IRouter的http api请求处理类
This commit is contained in:
@@ -55,7 +55,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Library\Serein.Library.csproj">
|
<ProjectReference Include="..\Library\Serein.Library.csproj">
|
||||||
<Project>{55C77D23-2FD3-43D1-918C-DC3DE9614F0F}</Project>
|
<Project>{9FCE93C2-2278-46F3-96AB-CDAAFF27A55F}</Project>
|
||||||
<Name>Serein.Library</Name>
|
<Name>Serein.Library</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -229,9 +229,9 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载项目文件
|
/// 加载项目文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="project"></param>
|
/// <param name="projectFile"></param>
|
||||||
/// <param name="filePath"></param>
|
/// <param name="filePath"></param>
|
||||||
void LoadProject(SereinProjectData project, string filePath);
|
void LoadProject(SereinProjectData projectFile, string filePath);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从文件中加载Dll
|
/// 从文件中加载Dll
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
|
||||||
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
|
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -96,27 +96,48 @@ namespace Serein.Library.Utils
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 尝试从容器中获取对象,如果不存在目标类型的对象,则将类型信息登记到容器,并实例化注入依赖项。
|
/// 尝试从容器中获取对象,如果不存在目标类型的对象,则将类型信息登记到容器,并实例化注入依赖项。如果依然无法注册,则返回null。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object GetOrRegisterInstantiate(Type type)
|
public object GetOrRegisterInstantiate(Type type)
|
||||||
{
|
{
|
||||||
// 尝试从容器中获取对象
|
// 尝试从容器中获取对象
|
||||||
if (!_dependencies.TryGetValue(type.FullName, out object value))
|
if (!_dependencies.TryGetValue(type.FullName, out object value))
|
||||||
{
|
{
|
||||||
Register(type);// 注册类型信息
|
// 容器中不存在目标类型的对象
|
||||||
value = Instantiate(type); // 创建实例对象,并注入依赖
|
if (type.IsInterface)
|
||||||
_dependencies.TryAdd(type.FullName, value); // 登记到IOC容器中
|
{
|
||||||
|
if (_typeMappings.TryGetValue(type.FullName, out Type implementationType))
|
||||||
|
{
|
||||||
|
// 是接口类型,存在注册信息
|
||||||
|
Register(type);// 注册类型信息
|
||||||
|
value = Instantiate(implementationType); // 创建实例对象,并注入依赖
|
||||||
|
_dependencies.TryAdd(type.FullName, value); // 登记到IOC容器中
|
||||||
|
_typeMappings.TryRemove(type.FullName, out _); // 取消类型的注册信息
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//需要获取接口类型的实例,但不存在类型注册信息
|
||||||
|
Console.WriteLine("当前需要获取接口,但没有注册实现类的类型,无法创建接口实例");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 不是接口,直接注册
|
||||||
|
Register(type);// 注册类型信息
|
||||||
|
value = Instantiate(type); // 创建实例对象,并注入依赖
|
||||||
|
_dependencies.TryAdd(type.FullName, value); // 登记到IOC容器中
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 尝试从容器中获取对象,如果不存在目标类型的对象,则将类型信息登记到容器,并实例化注入依赖项。
|
/// 尝试从容器中获取对象,如果不存在目标类型的对象,则将类型信息登记到容器,并实例化注入依赖项。如果依然无法注册,则返回null。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public T GetOrRegisterInstantiate<T>()
|
public T GetOrRegisterInstantiate<T>()
|
||||||
{
|
{
|
||||||
var value = Instantiate(typeof(T));
|
return (T)GetOrRegisterInstantiate(typeof(T));
|
||||||
return (T)value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
39
Library/Web/QueryStringParser.cs
Normal file
39
Library/Web/QueryStringParser.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Serein.Library.Web
|
||||||
|
{
|
||||||
|
internal class QueryStringParser
|
||||||
|
{
|
||||||
|
public static Dictionary<string, string> ParseQueryString(string query)
|
||||||
|
{
|
||||||
|
var result = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(query))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// 如果字符串以'?'开头,移除它
|
||||||
|
if (query.StartsWith("?"))
|
||||||
|
query = query.Substring(1);
|
||||||
|
|
||||||
|
// 拆分键值对
|
||||||
|
var pairs = query.Split('&');
|
||||||
|
foreach (var pair in pairs)
|
||||||
|
{
|
||||||
|
// 忽略空的键值对
|
||||||
|
if (string.IsNullOrEmpty(pair)) continue;
|
||||||
|
|
||||||
|
// 用等号分隔键和值
|
||||||
|
var keyValue = pair.Split(new[] { '=' }, 2);
|
||||||
|
|
||||||
|
var key = Uri.UnescapeDataString(keyValue[0]); // 解码键
|
||||||
|
var value = keyValue.Length > 1 ? Uri.UnescapeDataString(keyValue[1]) : string.Empty; // 解码值
|
||||||
|
|
||||||
|
result[key] = value; // 添加到字典中
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -137,8 +137,9 @@ namespace Serein.Library.Web
|
|||||||
if (!controllerType.IsClass || controllerType.IsAbstract) return false; // 如果不是类或者是抽象类,则直接返回
|
if (!controllerType.IsClass || controllerType.IsAbstract) return false; // 如果不是类或者是抽象类,则直接返回
|
||||||
|
|
||||||
var autoHostingAttribute = controllerType.GetCustomAttribute<AutoHostingAttribute>();
|
var autoHostingAttribute = controllerType.GetCustomAttribute<AutoHostingAttribute>();
|
||||||
|
var methods = controllerType.GetMethods().Where(m => m.GetCustomAttribute<WebApiAttribute>() != null).ToArray();
|
||||||
|
|
||||||
foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法
|
foreach (var method in methods) // 遍历控制器类型的所有方法
|
||||||
{
|
{
|
||||||
var routeAttribute = method.GetCustomAttribute<WebApiAttribute>(); // 获取方法上的 WebAPIAttribute 自定义属性
|
var routeAttribute = method.GetCustomAttribute<WebApiAttribute>(); // 获取方法上的 WebAPIAttribute 自定义属性
|
||||||
if (routeAttribute != null) // 如果存在 WebAPIAttribute 属性
|
if (routeAttribute != null) // 如果存在 WebAPIAttribute 属性
|
||||||
@@ -354,6 +355,7 @@ namespace Serein.Library.Web
|
|||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CS0168 // 声明了变量,但从未使用过
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -507,12 +509,17 @@ namespace Serein.Library.Web
|
|||||||
|
|
||||||
if (pathParts.Length > 1) // 如果包含查询字符串
|
if (pathParts.Length > 1) // 如果包含查询字符串
|
||||||
{
|
{
|
||||||
var queryParams = HttpUtility.ParseQueryString(pathParts[1]); // 解析查询字符串
|
//var queryParams = HttpUtility.ParseQueryString(pathParts[1]); // 解析查询字符串
|
||||||
|
//foreach (string key in queryParams) // 遍历查询字符串的键值对
|
||||||
foreach (string key in queryParams) // 遍历查询字符串的键值对
|
//{
|
||||||
|
// if (key == null) continue;
|
||||||
|
// routeValues[key] = queryParams[key]; // 将键值对添加到路由参数字典中
|
||||||
|
//}
|
||||||
|
var parsedQuery = QueryStringParser.ParseQueryString(pathParts[1]);
|
||||||
|
foreach (var kvp in parsedQuery)
|
||||||
{
|
{
|
||||||
if (key == null) continue;
|
//Console.WriteLine($"{kvp.Key}: {kvp.Value}");
|
||||||
routeValues[key] = queryParams[key]; // 将键值对添加到路由参数字典中
|
routeValues[kvp.Key] = kvp.Value; // 将键值对添加到路由参数字典中
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.Attributes;
|
||||||
|
using Serein.Library.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -13,9 +15,12 @@ namespace Serein.Library.Web
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class WebServer
|
public class WebServer
|
||||||
{
|
{
|
||||||
[AutoHosting]
|
[AutoInjection]
|
||||||
public IRouter Router { get; set; } // 路由器
|
public IRouter Router { get; set; } // 路由器
|
||||||
|
|
||||||
|
[AutoInjection]
|
||||||
|
public NodeRunCts nodeRunCts { get; set; }
|
||||||
|
|
||||||
private HttpListener listener; // HTTP 监听器
|
private HttpListener listener; // HTTP 监听器
|
||||||
private RequestLimiter requestLimiter; //接口防刷
|
private RequestLimiter requestLimiter; //接口防刷
|
||||||
|
|
||||||
@@ -38,6 +43,21 @@ namespace Serein.Library.Web
|
|||||||
|
|
||||||
listener.Start(); // 开始监听
|
listener.Start(); // 开始监听
|
||||||
|
|
||||||
|
//_ = Task.Run(async () =>
|
||||||
|
//{
|
||||||
|
// while (true)
|
||||||
|
// {
|
||||||
|
// await Task.Delay(100);
|
||||||
|
// if (nodeRunCts.IsCancellationRequested)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// var context = await listener.GetContextAsync(); // 获取请求上下文
|
||||||
|
// ProcessRequestAsync(context); // 处理请求
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
while (listener.IsListening)
|
while (listener.IsListening)
|
||||||
@@ -46,6 +66,7 @@ namespace Serein.Library.Web
|
|||||||
ProcessRequestAsync(context); // 处理请求
|
ProcessRequestAsync(context); // 处理请求
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ using Serein.Library.Core.NodeFlow;
|
|||||||
using Serein.Library.Entity;
|
using Serein.Library.Entity;
|
||||||
using Serein.Library.Enums;
|
using Serein.Library.Enums;
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
|
using Serein.Library.Web;
|
||||||
using Serein.NodeFlow.Base;
|
using Serein.NodeFlow.Base;
|
||||||
using Serein.NodeFlow.Model;
|
using Serein.NodeFlow.Model;
|
||||||
|
|
||||||
@@ -173,6 +174,10 @@ namespace Serein.NodeFlow
|
|||||||
Context.SereinIoc.Build(); // 预防有人在加载时才注册类型,再绑定一次
|
Context.SereinIoc.Build(); // 预防有人在加载时才注册类型,再绑定一次
|
||||||
ExitAction = () =>
|
ExitAction = () =>
|
||||||
{
|
{
|
||||||
|
SereinIOC.Run<WebServer>(web => {
|
||||||
|
web?.Stop();
|
||||||
|
});
|
||||||
|
|
||||||
foreach (MethodDetails? md in exitMethods)
|
foreach (MethodDetails? md in exitMethods)
|
||||||
{
|
{
|
||||||
object?[]? data = [md.ActingInstance, args];
|
object?[]? data = [md.ActingInstance, args];
|
||||||
@@ -188,6 +193,9 @@ namespace Serein.NodeFlow
|
|||||||
}
|
}
|
||||||
FlowState = RunState.Completion;
|
FlowState = RunState.Completion;
|
||||||
FlipFlopState = RunState.Completion;
|
FlipFlopState = RunState.Completion;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
@@ -150,14 +150,14 @@ namespace Serein.WorkBench
|
|||||||
Shutdown(); // 关闭应用程序
|
Shutdown(); // 关闭应用程序
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//else if (1 == 1)
|
//else if (1 == 1)
|
||||||
//{
|
//{
|
||||||
// string filePath = @"F:\临时\project\new project.dnf";
|
// string filePath = @"F:\临时\project\new project.dnf";
|
||||||
// //string filePath = @"D:\Project\C#\DynamicControl\SereinFlow\.Output\Debug\net8.0-windows7.0\U9 project.dnf";
|
// //string filePath = @"D:\Project\C#\DynamicControl\SereinFlow\.Output\Debug\net8.0-windows7.0\U9 project.dnf";
|
||||||
// string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
// string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||||
// App.FData = JsonConvert.DeserializeObject<SereinOutputFileData>(content);
|
// App.FData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||||
// App.FileDataPath = filePath;//System.IO.Path.GetDirectoryName(filePath)!;
|
// App.FileDataPath = filePath;//System.IO.Path.GetDirectoryName(filePath)!;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user