重写了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

@@ -500,7 +500,7 @@ namespace Serein.Library.Api
/// 清理加载的DLL待更改
/// </summary>
void ClearAll();
/// <summary>
/// 开始运行
@@ -549,6 +549,11 @@ namespace Serein.Library.Api
/// <param name="nodeGuid">待移除的节点Guid</param>
void RemoteNode(string nodeGuid);
// 启动触发器
void ActivateFlipflopNode(string nodeGuid);
void TerminateFlipflopNode(string nodeGuid);
/// <summary>
/// 设置节点中断级别
/// </summary>
@@ -612,7 +617,6 @@ namespace Serein.Library.Api
#endregion
#region UI视觉
/// <summary>

View File

@@ -8,6 +8,9 @@ using static Serein.Library.Utils.EmitHelper;
namespace Serein.Library.Entity
{
/// <summary>
/// 委托描述
/// </summary>
public class DelegateDetails
{
public DelegateDetails(EmitMethodType EmitMethodType, Delegate EmitDelegate)

View File

@@ -22,7 +22,7 @@ namespace Serein.Library.Enums
Exit,
/// <summary>
/// 触发器
/// 触发器(建议手动设置返回类型,方便视图直观)
/// </summary>
Flipflop,
/// <summary>

View File

@@ -51,7 +51,7 @@ namespace Serein.Library.Web
[AttributeUsage(AttributeTargets.Method)]
public class WebApiAttribute : Attribute
{
public API Http; // HTTP 请求类型
public ApiType ApiType; // HTTP 请求类型
public string Url; // URL 路径
/// <summary>
/// 方法名称不作为url的部分
@@ -68,15 +68,15 @@ namespace Serein.Library.Web
/// </summary>
/// <param name="http"></param>
/// <param name="url"></param>
public WebApiAttribute(API http = API.POST, bool isUrl = true, string url = "")
public WebApiAttribute(ApiType http = ApiType.POST, bool isUrl = true, string url = "")
{
Http = http;
ApiType = http;
Url = url;
IsUrl = isUrl;
}
}
public enum API
public enum ApiType
{
POST,
GET,

View File

@@ -2,14 +2,18 @@
using Newtonsoft.Json.Linq;
using Serein.Library.Api;
using Serein.Library.Attributes;
using Serein.Library.Entity;
using Serein.Library.Utils;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using System.Web;
@@ -20,10 +24,199 @@ namespace Serein.Library.Web
{
public interface IRouter
{
bool RegisterController(Type controllerType);
void AddHandle(Type controllerType);
Task<bool> ProcessingAsync(HttpListenerContext context);
}
public class ApiHandleConfig
{
private readonly Delegate EmitDelegate;
private readonly EmitHelper.EmitMethodType EmitMethodType;
public enum PostArgType
{
None,
IsUrlData,
IsBobyData,
}
public ApiHandleConfig(MethodInfo methodInfo)
{
EmitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out EmitDelegate);
var parameterInfos = methodInfo.GetParameters();
ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray();
ParameterName = parameterInfos.Select(t => t.Name.ToLower()).ToArray();
PostArgTypes = parameterInfos.Select(p =>
{
bool isUrlData = p.GetCustomAttribute(typeof(UrlAttribute)) != null;
bool isBobyData = p.GetCustomAttribute(typeof(BobyAttribute)) != null;
if (isBobyData)
{
return PostArgType.IsBobyData;
}
else if (isUrlData)
{
return PostArgType.IsUrlData;
}
else
{
return PostArgType.None;
}
}).ToArray();
}
private readonly PostArgType[] PostArgTypes;
private readonly string[] ParameterName;
private readonly Type[] ParameterType;
public async Task<object> HandleGet(object instance, Dictionary<string, string> routeData)
{
object[] args = new object[ParameterType.Length];
for (int i = 0; i < ParameterType.Length; i++)
{
var type = ParameterType[i];
var argName = ParameterName[i];
if (routeData.TryGetValue(argName, out var argValue))
{
if (type == typeof(string))
{
args[i] = argValue;
}
else // if (type.IsValueType)
{
args[i] = JsonConvert.DeserializeObject(argValue, type);
}
}
else
{
args[i] = type.IsValueType ? Activator.CreateInstance(type) : null;
}
}
object result;
try
{
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask)
{
result = await hasResultTask(instance, args);
}
else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task)
{
await task.Invoke(instance, args);
result = null;
}
else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func<object, object[], object> func)
{
result = func.Invoke(instance, args);
}
else
{
result = null;
}
}
catch (Exception ex)
{
result = null;
await Console.Out.WriteLineAsync(ex.Message);
}
return result;
}
public async Task<object> HandlePost(object instance, JObject jsonObject, Dictionary<string, string> routeData)
{
object[] args = new object[ParameterType.Length];
for (int i = 0; i < ParameterType.Length; i++)
{
var type = ParameterType[i];
var argName = ParameterName[i];
if (PostArgTypes[i] == PostArgType.IsUrlData)
{
if (routeData.TryGetValue(argName, out var argValue))
{
if (type == typeof(string))
{
args[i] = argValue;
}
else // if (type.IsValueType)
{
args[i] = JsonConvert.DeserializeObject(argValue, type);
}
}
else
{
args[i] = type.IsValueType ? Activator.CreateInstance(type) : null;
}
}
else if (PostArgTypes[i] == PostArgType.IsBobyData)
{
args[i] = jsonObject;
}
else
{
var jsonValue = jsonObject.GetValue(argName);
if (jsonValue is null)
{
// 值类型返回默认值引用类型返回null
args[i] = type.IsValueType ? Activator.CreateInstance(type) : null;
}
else
{
args[i] = jsonValue.ToObject(type);
}
}
}
object result;
try
{
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask)
{
result = await hasResultTask(instance, args);
}
else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task)
{
await task.Invoke(instance, args);
result = null;
}
else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func<object, object[], object> func)
{
result = func.Invoke(instance, args);
}
else
{
result = null;
}
}
catch (Exception ex)
{
result = null;
await Console.Out.WriteLineAsync(ex.Message);
}
return result;
}
}
/// <summary>
/// 路由注册与解析
/// </summary>
@@ -35,30 +228,30 @@ namespace Serein.Library.Web
/// <summary>
/// 控制器实例对象的类型,每次调用都会重新实例化,[Url - ControllerType]
/// </summary>
private readonly ConcurrentDictionary<string, Type> _controllerTypes; // 存储控制器类型
private readonly ConcurrentDictionary<string, Type> _controllerTypes = new ConcurrentDictionary<string, Type>();
/// <summary>
/// 用于存储路由信息,[GET|POST - [Url - Method]]
/// </summary>
private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, MethodInfo>> _routes;
//private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, MethodInfo>> _routes = new ConcurrentDictionary<string, ConcurrentDictionary<string, MethodInfo>>();
private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, ApiHandleConfig>> HandleModels = new ConcurrentDictionary<string, ConcurrentDictionary<string, ApiHandleConfig>>();
// private readonly ILoggerService loggerService; // 用于存储路由信息
//private Type PostRequest;
public Router(ISereinIOC SereinIOC)
{
this.SereinIOC = SereinIOC;
_routes = new ConcurrentDictionary<string, ConcurrentDictionary<string, MethodInfo>>(); // 初始化路由字典
_controllerTypes = new ConcurrentDictionary<string, Type>(); // 初始化控制器实例对象字典
foreach (API method in Enum.GetValues(typeof(API))) // 遍历 HTTP 枚举类型的所有值
foreach (ApiType method in Enum.GetValues(typeof(ApiType))) // 遍历 HTTP 枚举类型的所有值
{
_routes.TryAdd(method.ToString(), new ConcurrentDictionary<string, MethodInfo>()); // 初始化每种 HTTP 方法对应的路由字典
HandleModels.TryAdd(method.ToString(), new ConcurrentDictionary<string, ApiHandleConfig>()); // 初始化每种 HTTP 方法对应的路由字典
}
#if false
Type baseAttribute = typeof(AutoHostingAttribute);
Type baseController = typeof(ControllerBase);
// 获取当前程序集
Assembly assembly = Assembly.GetExecutingAssembly();
// 获取包含“Controller”名称的类型
@@ -69,9 +262,44 @@ namespace Serein.Library.Web
foreach (var controllerType in controllerTypes)
{
RegisterController(controllerType);
}
}
#endif
}
public void AddHandle(Type controllerType)
{
if (!controllerType.IsClass || controllerType.IsAbstract) return; // 如果不是类或者是抽象类,则直接返回
var autoHostingAttribute = controllerType.GetCustomAttribute<AutoHostingAttribute>();
var methods = controllerType.GetMethods().Where(m => m.GetCustomAttribute<WebApiAttribute>() != null).ToArray();
foreach (var method in methods) // 遍历控制器类型的所有方法
{
var routeAttribute = method.GetCustomAttribute<WebApiAttribute>(); // 获取方法上的 WebAPIAttribute 自定义属性
if (routeAttribute is null) // 如果存在 WebAPIAttribute 属性
{
continue;
}
var url = AddRoutesUrl(autoHostingAttribute, routeAttribute, controllerType, method);
if (url is null) continue;
Console.WriteLine(url);
var apiType = routeAttribute.ApiType.ToString();
var config = new ApiHandleConfig(method);
if(!HandleModels.TryGetValue(apiType, out var configs))
{
configs = new ConcurrentDictionary<string, ApiHandleConfig>();
HandleModels[apiType] = configs;
}
configs.TryAdd(url, config);
_controllerTypes.TryAdd(url,controllerType);
}
return;
}
/// <summary>
/// 在外部调用API后解析路由调用对应的方法
/// </summary>
@@ -84,14 +312,14 @@ namespace Serein.Library.Web
var url = request.Url; // 获取请求的 URL
var httpMethod = request.HttpMethod; // 获取请求的 HTTP 方法
var template = request.Url.AbsolutePath.ToLower();
if (!_routes[httpMethod].TryGetValue(template, out MethodInfo method))
if (!_controllerTypes.TryGetValue(template, out Type controllerType))
{
return false;
}
var routeValues = GetUrlData(url); // 解析 URL 获取路由参数
ControllerBase controllerInstance = (ControllerBase)SereinIOC.Instantiate(_controllerTypes[template]);// 使用反射创建控制器实例
ControllerBase controllerInstance = (ControllerBase)SereinIOC.Instantiate(controllerType);
if (controllerInstance is null)
{
@@ -99,195 +327,51 @@ namespace Serein.Library.Web
}
controllerInstance.Url = url.AbsolutePath;
if (!HandleModels.TryGetValue(httpMethod, out var modules))
{
return false;
}
if (!modules.TryGetValue(template,out var config))
{
return false;
}
dynamic invokeResult;
switch (httpMethod)
{
case "GET":
invokeResult = config.HandleGet(controllerInstance, routeValues);
break;
case "POST":
var requestBody = await ReadRequestBodyAsync(request); // 读取请求体内容
controllerInstance.BobyData = requestBody;
var requestJObject = JObject.Parse(requestBody);
invokeResult = config.HandlePost(controllerInstance, requestJObject, routeValues);
break;
default:
invokeResult = null;
break;
}
object result;
try
{
object result;
switch (httpMethod) // 根据请求的 HTTP 方法执行不同的操作
{
case "GET": // 如果是 GET 请求传入方法、控制器、url参数
// loggerService.Information(GetLog(template));
result = InvokeControllerMethodWithRouteValues(method, controllerInstance, routeValues);
break;
case "POST": // POST 请求传入方法、控制器、请求体内容url参数
var requestBody = await ReadRequestBodyAsync(request); // 读取请求体内容
controllerInstance.BobyData = requestBody;
var requestJObject = JObject.Parse(requestBody); //requestBody.FromJSON<JObject>();
// loggerService.Information(GetLog(template, requestBody));
result = InvokeControllerMethod(method, controllerInstance, requestJObject, routeValues);
break;
default:
result = null;
break;
}
Return(response, result); // 返回结果
return true;
result = invokeResult.Result;
}
catch (Exception ex)
catch (Exception)
{
response.StatusCode = (int)HttpStatusCode.NotFound; // 返回 404 错误
Return(response, ex.Message); // 返回结果
return true;
}
}
/// <summary>
/// 自动注册并实例化控制器类型
/// </summary>
/// <param name="controllerType"></param>
public bool RegisterController(Type controllerType) // 方法声明,用于注册并实例化控制器类型
{
if (!controllerType.IsClass || controllerType.IsAbstract) return false; // 如果不是类或者是抽象类,则直接返回
var autoHostingAttribute = controllerType.GetCustomAttribute<AutoHostingAttribute>();
var methods = controllerType.GetMethods().Where(m => m.GetCustomAttribute<WebApiAttribute>() != null).ToArray();
foreach (var method in methods) // 遍历控制器类型的所有方法
{
var routeAttribute = method.GetCustomAttribute<WebApiAttribute>(); // 获取方法上的 WebAPIAttribute 自定义属性
if (routeAttribute != null) // 如果存在 WebAPIAttribute 属性
{
var url = AddRoutesUrl(autoHostingAttribute, routeAttribute, controllerType, method);
Console.WriteLine(url);
if (url is null) continue;
_controllerTypes[url] = controllerType;
}
result = invokeResult;
}
Return(response, result); // 返回结果
return true;
}
#region Get Post对应的方法
/// <summary>
/// GET请求的控制器方法
/// </summary>
private object InvokeControllerMethodWithRouteValues(MethodInfo method, object controllerInstance, Dictionary<string, string> routeValues)
{
object[] parameters = GetMethodParameters(method, routeValues);
return InvokeMethod(method, controllerInstance, parameters);
}
/// <summary>
/// GET请求调用控制器方法传入参数
/// </summary>
/// <param name="method">方法</param>
/// <param name="controllerInstance">控制器实例</param>
/// <param name="methodParameters">参数列表</param>
/// <returns></returns>
private object InvokeMethod(MethodInfo method, object controllerInstance, object[] methodParameters)
{
object result = null;
try
{
result = method?.Invoke(controllerInstance, methodParameters);
}
catch (ArgumentException ex)
{
string targetType = ExtractTargetTypeFromExceptionMessage(ex.Message);
// 如果方法调用失败
result = new
{
error = $"函数签名类型[{targetType}]不符合",
};
}
catch (JsonSerializationException ex)
{
// 查找类型信息开始的索引
int startIndex = ex.Message.IndexOf("to type '") + "to type '".Length;
// 查找类型信息结束的索引
int endIndex = ex.Message.IndexOf("'", startIndex);
// 提取类型信息
string typeInfo = ex.Message.Substring(startIndex, endIndex - startIndex);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
return result; // 调用方法并返回结果
}
private readonly Dictionary<MethodInfo, ParameterInfo[]> methodParameterCache = new Dictionary<MethodInfo, ParameterInfo[]>();
/// <summary>
/// POST请求调用控制器方法传入参数
/// </summary>
public object InvokeControllerMethod(MethodInfo method, object controllerInstance, JObject requestData, Dictionary<string, string> routeValues)
{
if (requestData is null) return null;
ParameterInfo[] parameters;
object[] cachedMethodParameters;
if (!methodParameterCache.TryGetValue(method, out parameters))
{
parameters = method.GetParameters();
}
cachedMethodParameters = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
string paramName = parameters[i].Name;
bool isUrlData = parameters[i].GetCustomAttribute(typeof(UrlAttribute)) != null;
bool isBobyData = parameters[i].GetCustomAttribute(typeof(BobyAttribute)) != null;
if (isUrlData)
{
if (routeValues.ContainsKey(paramName))
{
cachedMethodParameters[i] = ConvertValue(routeValues[paramName], parameters[i].ParameterType);
}
else
{
cachedMethodParameters[i] = null;
}
}
else if (isBobyData)
{
cachedMethodParameters[i] = ConvertValue(requestData.ToString(), parameters[i].ParameterType);
}
else
{
if (requestData.ContainsKey(paramName))
{
var rd = requestData[paramName];
if (parameters[i].ParameterType == typeof(string))
{
cachedMethodParameters[i] = rd.ToString();
}
else if (parameters[i].ParameterType == typeof(bool))
{
cachedMethodParameters[i] = rd.ToBool();
}
else if (parameters[i].ParameterType == typeof(int))
{
cachedMethodParameters[i] = rd.ToInt();
}
else if (parameters[i].ParameterType == typeof(double))
{
cachedMethodParameters[i] = rd.ToDouble();
}
else
{
cachedMethodParameters[i] = ConvertValue(rd, parameters[i].ParameterType);
}
}
else
{
cachedMethodParameters[i] = null;
}
}
}
// 缓存方法和参数的映射
//methodParameterCache[method] = cachedMethodParameters;
// 调用方法
return method.Invoke(controllerInstance, cachedMethodParameters);
}
#endregion
#region
/// <summary>
/// 读取Body中的消息
/// </summary>
@@ -304,72 +388,6 @@ namespace Serein.Library.Web
}
}
/// <summary>
/// 检查方法入参参数类型,返回对应的入参数组
/// </summary>
/// <param name="method"></param>
/// <param name="routeValues"></param>
/// <returns></returns>
private object[] GetMethodParameters(MethodInfo method, Dictionary<string, string> routeValues)
{
ParameterInfo[] methodParameters = method.GetParameters();
object[] parameters = new object[methodParameters.Length];
for (int i = 0; i < methodParameters.Length; i++)
{
string paramName = methodParameters[i].Name;
if (routeValues.ContainsKey(paramName))
{
parameters[i] = ConvertValue(routeValues[paramName], methodParameters[i].ParameterType);
}
else
{
parameters[i] = null;
}
}
return parameters;
}
/// <summary>
/// 转为对应的类型
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <returns></returns>
private object ConvertValue(object value, Type targetType)
{
try
{
if (targetType == typeof(string))
{
return value;
}
else
{
return JsonConvert.DeserializeObject(value.ToString(), targetType);
}
}
catch (JsonReaderException ex)
{
Console.WriteLine(ex);
return value;
}
catch (JsonSerializationException ex)
{
// 如果无法转为对应的JSON对象
int startIndex = ex.Message.IndexOf("to type '") + "to type '".Length; // 查找类型信息开始的索引
int endIndex = ex.Message.IndexOf("'", startIndex); // 查找类型信息结束的索引
var typeInfo = ex.Message.Substring(startIndex, endIndex - startIndex); // 提取出错类型信息,该怎么传出去?
return null;
}
catch // (Exception ex)
{
return value;
}
}
/// <summary>
/// 返回响应消息
/// </summary>
@@ -449,7 +467,7 @@ namespace Serein.Library.Web
controllerName = autoHostingAttribute.Url;
}
var httpMethod = webAttribute.Http; // 获取 HTTP 方法
var httpMethod = webAttribute.ApiType; // 获取 HTTP 方法
var customUrl = webAttribute.Url; // 获取自定义 URL
string url;
@@ -466,7 +484,7 @@ namespace Serein.Library.Web
customUrl = CleanUrl(customUrl);
url = $"/{controllerName}/{method.Name}/{customUrl}".ToLower();// 清理自定义 URL并构建新的 URL
}
_routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中
//HandleModels[httpMethod.ToString()].TryAdd(url ); // 将 URL 和方法添加到对应的路由字典中
}
else
{
@@ -479,7 +497,7 @@ namespace Serein.Library.Web
customUrl = CleanUrl(customUrl);
url = $"/{controllerName}/{customUrl}".ToLower();// 清理自定义 URL并构建新的 URL
}
_routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中
// _routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中
}
return url;
@@ -539,7 +557,7 @@ namespace Serein.Library.Web
foreach (var kvp in parsedQuery)
{
//Console.WriteLine($"{kvp.Key}: {kvp.Value}");
routeValues[kvp.Key] = kvp.Value; // 将键值对添加到路由参数字典中
routeValues[kvp.Key.ToLower()] = kvp.Value; // 将键值对添加到路由参数字典中
}
}
@@ -567,7 +585,6 @@ namespace Serein.Library.Web
return null;
}
#endregion
}

View File

@@ -10,9 +10,18 @@ namespace Serein.Library.Network.WebSocketCommunication
[AttributeUsage(AttributeTargets.Method)]
public sealed class AutoSocketHandleAttribute : Attribute
{
public string ThemeValue;
public string ThemeValue = string.Empty;
public bool IsReturnValue = true;
//public Type DataType;
}
public class SocketHandleModel
{
public string ThemeValue { get; set; } = string.Empty;
public bool IsReturnValue { get; set; } = true;
}
[AttributeUsage(AttributeTargets.Class)]
public sealed class AutoSocketModuleAttribute : Attribute
{

View File

@@ -20,17 +20,24 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
private readonly Delegate EmitDelegate;
private readonly EmitHelper.EmitMethodType EmitMethodType;
public MyHandleConfig(ISocketControlBase instance, MethodInfo methodInfo)
private Action<Exception, Action<object>> OnExceptionTracking;
public MyHandleConfig(SocketHandleModel model,ISocketControlBase instance, MethodInfo methodInfo, Action<Exception, Action<object>> onExceptionTracking)
{
EmitMethodType = EmitHelper.CreateDynamicMethod(methodInfo,out EmitDelegate);
this.Model = model;
Instance = instance;
var parameterInfos = methodInfo.GetParameters();
ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray();
ParameterName = parameterInfos.Select(t => t.Name).ToArray();
this.HandleGuid = instance.HandleGuid;
this.OnExceptionTracking = onExceptionTracking;
}
public ISocketControlBase Instance { get; private set; }
private SocketHandleModel Model;
private ISocketControlBase Instance;
public Guid HandleGuid { get; }
private string[] ParameterName;
private Type[] ParameterType;
@@ -92,30 +99,44 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
}
Stopwatch sw = new Stopwatch();
sw.Start();
//Stopwatch sw = new Stopwatch();
//sw.Start();
object result;
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask)
try
{
result = await hasResultTask(Instance, args);
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask)
{
result = await hasResultTask(Instance, args);
}
else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task)
{
await task.Invoke(Instance, args);
result = null;
}
else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func<object, object[], object> func)
{
result = func.Invoke(Instance, args);
}
else
{
result = null;
}
}
else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task)
catch (Exception ex)
{
await task.Invoke(Instance, args);
result = null;
}
else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func<object, object[], object> func)
{
result = func.Invoke(Instance, args);
}
else
{
throw new NotImplementedException("构造委托无法正确调用");
}
sw.Stop();
Console.WriteLine($"Emit Invoke{sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
await Console.Out.WriteLineAsync(ex.Message);
this.OnExceptionTracking.Invoke(ex, (async data =>
{
if(result != null && result.GetType().IsClass)
var jsonText = JsonConvert.SerializeObject(data);
await RecoverAsync.Invoke(jsonText);
}));
}
//sw.Stop();
//Console.WriteLine($"Emit Invoke{sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
if(Model.IsReturnValue && result != null && result.GetType().IsClass)
{
var reusltJsonText = JsonConvert.SerializeObject(result);
_ = RecoverAsync.Invoke($"{reusltJsonText}");

View File

@@ -18,25 +18,30 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
public string ThemeJsonKey { get; }
public string DataJsonKey { get; }
public ConcurrentDictionary<string, MyHandleConfig> MyHandleConfigs = new ConcurrentDictionary<string, MyHandleConfig>();
public void AddHandleConfigs(string themeValue, ISocketControlBase instance, MethodInfo methodInfo)
public void AddHandleConfigs(SocketHandleModel model, ISocketControlBase instance, MethodInfo methodInfo
, Action<Exception, Action<object>> onExceptionTracking)
{
if (!MyHandleConfigs.ContainsKey(themeValue))
if (!MyHandleConfigs.ContainsKey(model.ThemeValue))
{
var myHandleConfig = new MyHandleConfig(instance, methodInfo);
MyHandleConfigs[themeValue] = myHandleConfig;
var myHandleConfig = new MyHandleConfig(model,instance, methodInfo, onExceptionTracking);
MyHandleConfigs[model.ThemeValue] = myHandleConfig;
}
}
public void ResetConfig(ISocketControlBase socketControlBase)
public bool ResetConfig(ISocketControlBase socketControlBase)
{
foreach (var kv in MyHandleConfigs.ToArray())
{
var config = kv.Value;
if (config.Instance.HandleGuid.Equals(socketControlBase.HandleGuid))
if (config.HandleGuid.Equals(socketControlBase.HandleGuid))
{
MyHandleConfigs.TryRemove(kv.Key, out _);
}
}
return MyHandleConfigs.Count == 0;
}
public void ResetConfig()

View File

@@ -28,7 +28,11 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
public ConcurrentDictionary<(string, string), MyHandleModule> MyHandleModuleDict
= new ConcurrentDictionary<(string, string), MyHandleModule>();
private Action<Exception, Action<object>> _onExceptionTracking;
/// <summary>
/// 异常跟踪
/// </summary>
public event Action<Exception, Action<object>> OnExceptionTracking;
private MyHandleModule AddMyHandleModule(string themeKeyName, string dataKeyName)
{
@@ -52,13 +56,14 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
var themeKeyName = moduleAttribute.JsonThemeField;
var dataKeyName = moduleAttribute.JsonDataField;
var key = (themeKeyName, dataKeyName);
if (MyHandleModuleDict.TryRemove(key, out var myHandleModules))
if (MyHandleModuleDict.TryGetValue(key, out var myHandleModules))
{
myHandleModules.ResetConfig(socketControlBase);
var isRemote = myHandleModules.ResetConfig(socketControlBase);
if (isRemote) MyHandleModuleDict.TryGetValue(key, out _);
}
}
public void AddModule(ISocketControlBase socketControlBase)
public void AddModule(ISocketControlBase socketControlBase, Action<Exception, Action<object>> onExceptionTracking)
{
var type = socketControlBase.GetType();
var moduleAttribute = type.GetCustomAttribute<AutoSocketModuleAttribute>();
@@ -67,10 +72,9 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
return;
}
// 添加处理模块
var themeKey = moduleAttribute.JsonThemeField;
var dataKey = moduleAttribute.JsonDataField;
var handlemodule = AddMyHandleModule(themeKey, dataKey);
var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Select(method =>
@@ -78,23 +82,35 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
var methodsAttribute = method.GetCustomAttribute<AutoSocketHandleAttribute>();
if (methodsAttribute is null)
{
return (string.Empty, null);
return (null, null);
}
else
{
if (string.IsNullOrEmpty(methodsAttribute.ThemeValue))
{
methodsAttribute.ThemeValue = method.Name;
}
var model = new SocketHandleModel
{
IsReturnValue = methodsAttribute.IsReturnValue,
ThemeValue = methodsAttribute.ThemeValue,
};
var value = methodsAttribute.ThemeValue;
return (value, method);
return (model, method);
}
})
.Where(x => !string.IsNullOrEmpty(x.value)).ToList();
.Where(x => !(x.model is null)).ToList();
if (methods.Count == 0)
{
return;
}
foreach ((var value, var method) in methods)
Console.WriteLine($"add websocket handle model :");
Console.WriteLine($"theme key, data key : {themeKey}, {dataKey}");
foreach ((var model, var method) in methods)
{
handlemodule.AddHandleConfigs(value, socketControlBase, method);
Console.WriteLine($"theme value : {model.ThemeValue}");
handlemodule.AddHandleConfigs(model, socketControlBase, method, onExceptionTracking);
}
}
@@ -106,7 +122,9 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
{
foreach (var module in MyHandleModuleDict.Values)
{
module.HandleSocketMsg(RecoverAsync, json);
}
});

View File

@@ -14,15 +14,8 @@ using System.Threading.Tasks;
namespace Serein.Library.Network.WebSocketCommunication
{
[AutoRegister]
public class WebSocketServer
{
public WebSocketServer()
{
}
public SocketMsgHandleHelper MsgHandleHelper { get; } = new SocketMsgHandleHelper();
HttpListener listener;

View File

@@ -56,7 +56,7 @@ namespace Serein.Library.Attributes
/// <summary>
/// 建议触发器手动设置返回类型
/// 生成的节点类型
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class NodeActionAttribute : Attribute