using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using System.Threading; 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,int age) /// Json示例:{ "theme":"AddUser", //【ThemeKey】 /// "data": { // 【DataKey】 /// "name":"张三", /// "age":35, } } /// WebSocket中收到以上该Json时,通过ThemeKey获取到"AddUser",然后找到AddUser()方法 /// 然后根据方法入参名称,从data对应的json数据中取出"name""age"对应的数据作为入参进行调用。AddUser("张三",35) /// /// [AttributeUsage(AttributeTargets.Class)] public sealed class AutoSocketModuleAttribute : Attribute { /// /// 业务标识 /// public string ThemeKey; /// /// 数据标识 /// public string DataKey; /// /// ID标识 /// public string MsgIdKey; } /// /// 作用:WebSocket中处理Json时,将通过Json中ThemeKey 对应的内容(ThemeValue)自动路由到相应方法进行处理,同时要求Data中必须存在对应入参。 /// 如果没有显式设置 ThemeValue,将默认使用方法名称作为ThemeValue。 /// 如果没有显式设置 IsReturnValue 标记为 false ,当方法顺利完成(没有抛出异常,且返回对象非null),会自动转为json文本发送回去 /// 如果没有显式设置 ArgNotNull 标记为 false ,当外部尝试调用时,若 Json Data 不包含响应的数据,将会被忽略此次调用 /// 如果返回类型为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; /// /// 标记方法执行完成后是否需要将结果发送。 /// 注意以下返回值,返回的 json 中将不会新建 DataKey 字段: /// 1.返回类型为 void /// 2.返回类型为 Task /// 2.返回类型为 Unit /// 补充:如果返回类型是Task<TResult> /// 会进行异步等待,当Task结束后,自动获取TResult进行发送(请避免Task<Task<TResult>>诸如此类的Task泛型嵌套) /// public bool IsReturnValue = true; /// /// 表示该方法所有入参不能为空(所需的参数在请求Json的Data不存在) /// 若有一个参数无法从data获取,则不会进行调用该方法 /// 如果设置该属性为 false ,但某些入参不能为空,而不希望在代码中进行检查,请为入参添加[NotNull]/[Needful]特性 /// public bool ArgNotNull = true; } /// /// 使用 DataKey 整体数据 /// [AttributeUsage(AttributeTargets.Parameter)] public sealed class UseDataAttribute : Attribute { } /// /// 使用 MsgIdKey 整体数据 /// [AttributeUsage(AttributeTargets.Parameter)] public sealed class UseMsgIdAttribute : Attribute { } internal class WebSocketHandleConfiguration : HandleConfiguration { /// /// 主题 /// public string ThemeValue { get; set; } = string.Empty; } /// /// socket模块处理数据配置 /// public class HandleConfiguration { /// /// Emit委托 /// public DelegateDetails DelegateDetails { get; set; } /// /// 未捕获的异常跟踪 /// public Action> OnExceptionTracking { get; set; } /// /// 所使用的实例 /// public ISocketHandleModule Instance { get; set; } /// /// 是否需要返回 /// public bool IsReturnValue { get; set; } = true; /// /// 是否要求必须不为null /// public bool ArgNotNull { get; set; } = true; /// /// 是否使Data整体内容作为入参参数 /// public bool[] UseData { get; set; } /// /// 是否使用消息ID作为入参参数 /// public bool[] UseMsgId { get; set; } /// /// 参数名称 /// public string[] ParameterName { get; set; } /// /// 参数类型 /// public Type[] ParameterType { get; set; } /// /// 是否检查变量为空 /// public bool[] IsCheckArgNotNull { get; set; } } }