From 7c85d6eabe1a192a1ab5a74c938db8bc92015f15 Mon Sep 17 00:00:00 2001 From: Joes Date: Mon, 20 May 2024 09:45:00 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=8D=95=E8=AF=8D?= =?UTF-8?q?=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Cyaim.WebSocketServer.Example.csproj | 5 - .../Cyaim.WebSocketServer.csproj | 4 - .../Attributes/WebSocketAttribute.cs | 10 +- .../Cluster/GlobalClusterCenter.cs | 6 +- .../Configures/ClusterOption.cs | 13 +- .../Configures/ConstructorParameter.cs | 7 +- .../Configures/WatchAssemblyContext.cs | 10 +- .../Configures/WebSocketEndPoint.cs | 5 +- .../Configures/WebSocketRouteOption.cs | 43 +- .../Infrastructure/Handlers/DataTypes.cs | 337 +++--- .../Handlers/IWebSocketHandler.cs | 8 +- .../Handlers/MvcHandler/MvcChannelHandler.cs | 994 ++++++++---------- .../Handlers/MvcHandler/MvcResponseScheme.cs | 43 +- .../Infrastructure/WebSocketManager.cs | 69 +- ...bSocketRouteServiceCollectionExtensions.cs | 149 +-- .../net6.0/Cyaim.WebSocketServer.deps.json | 79 -- .../net7.0/Cyaim.WebSocketServer.deps.json | 67 -- .../net8.0/Cyaim.WebSocketServer.deps.json | 46 - 18 files changed, 741 insertions(+), 1154 deletions(-) delete mode 100644 Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net6.0/Cyaim.WebSocketServer.deps.json delete mode 100644 Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net7.0/Cyaim.WebSocketServer.deps.json delete mode 100644 Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net8.0/Cyaim.WebSocketServer.deps.json diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer.Example/Cyaim.WebSocketServer.Example.csproj b/Cyaim.WebSocketServer/Cyaim.WebSocketServer.Example/Cyaim.WebSocketServer.Example.csproj index 9e15f10..d99e4ce 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer.Example/Cyaim.WebSocketServer.Example.csproj +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer.Example/Cyaim.WebSocketServer.Example.csproj @@ -12,9 +12,4 @@ - - - - - diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Cyaim.WebSocketServer.csproj b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Cyaim.WebSocketServer.csproj index 35d1f11..7e62899 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Cyaim.WebSocketServer.csproj +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Cyaim.WebSocketServer.csproj @@ -25,10 +25,6 @@ README.md - - E:\WorkSpaces\WebSocketServer\Cyaim.WebSocketServer\Cyaim.WebSocketServer\Cyaim.WebSocketServer.xml - - diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Attributes/WebSocketAttribute.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Attributes/WebSocketAttribute.cs index e7099ab..ebb246c 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Attributes/WebSocketAttribute.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Attributes/WebSocketAttribute.cs @@ -1,21 +1,17 @@ using System; -using System.Collections.Generic; -using System.Text; namespace Cyaim.WebSocketServer.Infrastructure.Attributes { /// /// WebSocket Endpoint mark /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + [AttributeUsage(AttributeTargets.Method)] public class WebSocketAttribute : Attribute { /// /// Mark action use action name /// - public WebSocketAttribute() - { - } + public WebSocketAttribute() { } /// /// Mark action use method value @@ -31,4 +27,4 @@ public WebSocketAttribute(string method) : this() /// public string Method { get; set; } } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Cluster/GlobalClusterCenter.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Cluster/GlobalClusterCenter.cs index a107af2..14575fc 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Cluster/GlobalClusterCenter.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Cluster/GlobalClusterCenter.cs @@ -1,8 +1,6 @@ using Cyaim.WebSocketServer.Infrastructure.Configures; -using System; using System.Collections.Generic; using System.Net.WebSockets; -using System.Text; namespace Cyaim.WebSocketServer.Infrastructure.Cluster { @@ -17,8 +15,8 @@ public static class GlobalClusterCenter public static ClusterOption ClusterContext { get; set; } /// - /// All nodes + /// All nodes /// public static List Nodes { get; set; } } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/ClusterOption.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/ClusterOption.cs index c428b4f..6ae0039 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/ClusterOption.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/ClusterOption.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Cyaim.WebSocketServer.Infrastructure.Configures +namespace Cyaim.WebSocketServer.Infrastructure.Configures { /// /// Cluster configure @@ -30,10 +26,8 @@ public class ClusterOption /// Only NodeLevel are valid for Master. /// public bool IsEnableLoadBalance { get; set; } - } - /// /// Service node /// @@ -43,9 +37,10 @@ public enum ServiceLevel /// Master node /// Master, + /// /// Slave node /// - Slave, + Slave } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/ConstructorParameter.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/ConstructorParameter.cs index fd2bf86..12c799a 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/ConstructorParameter.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/ConstructorParameter.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Text; +using System.Reflection; namespace Cyaim.WebSocketServer.Infrastructure.Configures { @@ -20,4 +17,4 @@ public struct ConstructorParameter /// public ParameterInfo[] ParameterInfos { get; set; } } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WatchAssemblyContext.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WatchAssemblyContext.cs index bd09e15..88f6bac 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WatchAssemblyContext.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WatchAssemblyContext.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Dynamic; using System.Reflection; -using System.Text; namespace Cyaim.WebSocketServer.Infrastructure.Configures { @@ -18,7 +16,7 @@ public class WatchAssemblyContext public string WatchAssemblyPath { get; set; } /// - /// Type in assemblys + /// Type in assemblies /// public List WatchAssemblyTypes { get; set; } @@ -41,13 +39,13 @@ public class WatchAssemblyContext /// Constructor parameter list /// K class type,V class constructor parameter list /// - public Dictionary CoustructorParameters { get; set; } + public Dictionary ConstructorParameters { get; set; } /// /// Constructor most parameter in class /// K Class type,V Constructor parameter /// - public Dictionary MaxCoustructorParameters { get; set; } + public Dictionary MaxConstructorParameters { get; set; } /// /// Method parameter list in class public method @@ -55,4 +53,4 @@ public class WatchAssemblyContext /// public Dictionary MethodParameters { get; set; } } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketEndPoint.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketEndPoint.cs index 7e23cd6..3e90224 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketEndPoint.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketEndPoint.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Reflection; -using System.Text; namespace Cyaim.WebSocketServer.Infrastructure.Configures { @@ -39,6 +37,5 @@ public class WebSocketEndPoint /// Endpoint where class /// public Type Class { get; set; } - } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs index 89df2f1..9fc7d89 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs @@ -4,9 +4,6 @@ using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Text; using System.Text.Json; using System.Threading.Tasks; @@ -15,7 +12,7 @@ namespace Cyaim.WebSocketServer.Infrastructure.Configures /// /// WebSocketRoute run parameter /// - public class WebSocketRouteOption + public sealed class WebSocketRouteOption { /// /// Dependency injection container provider,Set on UseWebSocketServer @@ -85,7 +82,6 @@ public class WebSocketRouteOption /// logger /// WebSocket configure option /// - public delegate Task WebSocketChannelHandler(HttpContext context, ILogger logger, WebSocketRouteOption webSocketOptions); /// @@ -111,7 +107,7 @@ public class WebSocketRouteOption /// /// /// - public virtual Task OnBeforeConnection(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) + public Task OnBeforeConnection(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) { if (BeforeConnectionEvent != null) { @@ -120,61 +116,62 @@ public virtual Task OnBeforeConnection(HttpContext context, WebSocketRoute return Task.FromResult(true); } - /// - /// Close connectioned handler + /// Close Connected handler /// /// /// /// /// /// - public delegate Task DisConnectionedHandler(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger); + public delegate Task DisConnectedHandler(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger); /// - /// Close connectioned call + /// Close Connected call /// - public event DisConnectionedHandler DisConnectionedEvent; + public event DisConnectedHandler DisConnectedEvent; /// - /// DisConnectionedEvent entry + /// DisConnectedEvent entry /// /// /// /// /// /// - public virtual Task OnDisConnectioned(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) + public Task OnDisConnected(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) { - if (DisConnectionedEvent != null) + if (DisConnectedEvent != null) { - return DisConnectionedEvent(context, webSocketOptions, channel, logger); + return DisConnectedEvent(context, webSocketOptions, channel, logger); } return Task.CompletedTask; } - #endregion + #endregion #region System.Text.Json Options + /// - /// JsonSerialiazerOptions + /// JsonSerializerOptions /// - public JsonSerializerOptions DefaultRequestJsonSerialiazerOptions { get; set; } = new JsonSerializerOptions + public JsonSerializerOptions DefaultRequestJsonSerializerOptions { get; set; } = new JsonSerializerOptions { // 设置为 true 以忽略属性名称的大小写 PropertyNameCaseInsensitive = true, - WriteIndented = false, + WriteIndented = false }; /// - /// JsonSerialiazerOptions + /// JsonSerializerOptions /// - public JsonSerializerOptions DefaultResponseJsonSerialiazerOptions { get; set; } = new JsonSerializerOptions + public JsonSerializerOptions DefaultResponseJsonSerializerOptions { get; set; } = new JsonSerializerOptions { // 设置为 true 以忽略属性名称的大小写 PropertyNameCaseInsensitive = true, - WriteIndented = false, + WriteIndented = false }; + #endregion } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/DataTypes.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/DataTypes.cs index cb23bea..fd24d75 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/DataTypes.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/DataTypes.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Text; using System.Text.Json; using System.Text.Json.Nodes; @@ -12,90 +9,35 @@ namespace Cyaim.WebSocketServer.Infrastructure.Handlers /// public static class DataTypes { - #region BaseType - /// - /// System.SByte - /// - public const string Type_SByte = "System.SByte"; - /// - /// System.Byte - /// - public const string Type_Byte = "System.Byte"; - /// - /// System.Int16 - /// - public const string Type_Short = "System.Int16"; - /// - /// System.UInt16 - /// - public const string Type_UShort = "System.UInt16"; - /// - /// System.Int32 - /// - public const string Type_Int = "System.Int32"; - /// - /// System.UInt32 - /// - public const string Type_UInt = "System.UInt32"; - /// - /// System.Int64 - /// - public const string Type_Long = "System.Int64"; - /// - /// System.UInt64 - /// - public const string Type_ULong = "System.UInt64"; - /// - /// System.Single - /// - public const string Type_Float = "System.Single"; - /// - /// System.Double - /// - public const string Type_Double = "System.Double"; - /// - /// System.Boolean - /// - public const string Type_Bool = "System.Boolean"; - /// - /// System.Char - /// - public const string Type_Char = "System.Char"; - /// - /// System.Decimal - /// - public const string Type_Decimal = "System.Decimal"; - /// - /// System.String - /// - public const string Type_String = "System.String"; - #endregion - /// /// System.DateTime /// - public const string Type_DateTime = "System.DateTime"; + private const string Type_DateTime = "System.DateTime"; + /// /// System.DateTimeOffset /// - public const string Type_DateTimeOffset = "System.DateTimeOffset"; + private const string Type_DateTimeOffset = "System.DateTimeOffset"; /// /// System.Text.Json.JsonNode /// - public const string Type_JsonNode = "System.Text.Json.JsonNode"; + private const string Type_JsonNode = "System.Text.Json.JsonNode"; + /// /// System.Text.Json.JsonObject /// - public const string Type_JsonObject = "System.Text.Json.JsonObject"; + private const string Type_JsonObject = "System.Text.Json.JsonObject"; + /// /// System.Text.Json.JsonArray /// - public const string Type_JsonArray = "System.Text.Json.JsonArray"; + private const string Type_JsonArray = "System.Text.Json.JsonArray"; + /// /// System.Text.Json.JsonValue /// - public const string Type_JsonValue = "System.Text.Json.JsonValue"; + private const string Type_JsonValue = "System.Text.Json.JsonValue"; /// /// JsonNode value to target type @@ -105,36 +47,28 @@ public static class DataTypes /// public static object ConvertTo(this Type type, JsonNode value) { - try + return type.FullName switch { - return type.FullName switch - { - Type_String => value.GetValue(), - Type_SByte => value.GetValue(), - Type_Byte => value.GetValue(), - Type_Short => value.GetValue(), - Type_UShort => value.GetValue(), - Type_Int => value.GetValue(), - Type_UInt => value.GetValue(), - Type_Long => value.GetValue(), - Type_ULong => value.GetValue(), - Type_Float => value.GetValue(), - Type_Double => value.GetValue(), - Type_Bool => value.GetValue(), - Type_DateTime => value.GetValue(), - Type_DateTimeOffset => value.GetValue(), - Type_Char => value.GetValue(), - Type_Decimal => value.GetValue(), - _ => JsonSerializer.Deserialize(value, type), - }; - } - catch (Exception) - { - throw; - } + Type_String => value.GetValue(), + Type_SByte => value.GetValue(), + Type_Byte => value.GetValue(), + Type_Short => value.GetValue(), + Type_UShort => value.GetValue(), + Type_Int => value.GetValue(), + Type_UInt => value.GetValue(), + Type_Long => value.GetValue(), + Type_ULong => value.GetValue(), + Type_Float => value.GetValue(), + Type_Double => value.GetValue(), + Type_Bool => value.GetValue(), + Type_DateTime => value.GetValue(), + Type_DateTimeOffset => value.GetValue(), + Type_Char => value.GetValue(), + Type_Decimal => value.GetValue(), + _ => value.Deserialize(type) + }; } - /// /// object to real type /// @@ -143,56 +77,47 @@ public static object ConvertTo(this Type type, JsonNode value) /// public static object ConvertTo(this Type type, object value) { - try + switch (type.FullName) { - switch (type.FullName) - { - case Type_String: - return Convert.ToString(value); - case Type_SByte: - return Convert.ToSByte(value); - case Type_Byte: - return Convert.ToByte(value); - case Type_Short: - return Convert.ToInt16(value); - case Type_UShort: - return Convert.ToUInt16(value); - case Type_Int: - return Convert.ToInt32(value); - case Type_UInt: - return Convert.ToUInt32(value); - case Type_Long: - return Convert.ToInt64(value); - case Type_ULong: - return Convert.ToUInt64(value); - case Type_Float: - return Convert.ToSingle(value); - case Type_Double: - return Convert.ToDouble(value); - case Type_Bool: - return Convert.ToBoolean(value); - case Type_Char: - return Convert.ToChar(value); - case Type_Decimal: - return Convert.ToChar(value); - case Type_DateTime: - return Convert.ToDateTime(value); - case Type_DateTimeOffset: - return DateTimeOffset.Parse(value.ToString()); - - case Type_JsonNode: - case Type_JsonObject: - case Type_JsonArray: - case Type_JsonValue: - return JsonNode.Parse(value.ToString()); - default: - return null; - } - } - catch (Exception) - { - - throw; + case Type_String: + return Convert.ToString(value); + case Type_SByte: + return Convert.ToSByte(value); + case Type_Byte: + return Convert.ToByte(value); + case Type_Short: + return Convert.ToInt16(value); + case Type_UShort: + return Convert.ToUInt16(value); + case Type_Int: + return Convert.ToInt32(value); + case Type_UInt: + return Convert.ToUInt32(value); + case Type_Long: + return Convert.ToInt64(value); + case Type_ULong: + return Convert.ToUInt64(value); + case Type_Float: + return Convert.ToSingle(value); + case Type_Double: + return Convert.ToDouble(value); + case Type_Bool: + return Convert.ToBoolean(value); + case Type_Char: + return Convert.ToChar(value); + case Type_Decimal: + return Convert.ToChar(value); + case Type_DateTime: + return Convert.ToDateTime(value); + case Type_DateTimeOffset: + return DateTimeOffset.Parse(value.ToString()); + case Type_JsonNode: + case Type_JsonObject: + case Type_JsonArray: + case Type_JsonValue: + return JsonNode.Parse(value.ToString()); + default: + return null; } } @@ -203,36 +128,102 @@ public static object ConvertTo(this Type type, object value) /// public static bool IsBasicType(this Type type) { - try + switch (type.FullName) { - switch (type.FullName) - { - case Type_String: - case Type_SByte: - case Type_Byte: - case Type_Short: - case Type_UShort: - case Type_Int: - case Type_UInt: - case Type_Long: - case Type_ULong: - case Type_Float: - case Type_Double: - case Type_Bool: - //case Type_DateTime: - //case Type_DateTimeOffset: - case Type_Char: - case Type_Decimal: - return true; - default: - return false; - } - } - catch (Exception) - { - - throw; + case Type_String: + case Type_SByte: + case Type_Byte: + case Type_Short: + case Type_UShort: + case Type_Int: + case Type_UInt: + case Type_Long: + case Type_ULong: + case Type_Float: + case Type_Double: + case Type_Bool: + //case Type_DateTime: + //case Type_DateTimeOffset: + case Type_Char: + case Type_Decimal: + return true; + default: + return false; } } + + #region BaseType + + /// + /// System.SByte + /// + private const string Type_SByte = "System.SByte"; + + /// + /// System.Byte + /// + private const string Type_Byte = "System.Byte"; + + /// + /// System.Int16 + /// + private const string Type_Short = "System.Int16"; + + /// + /// System.UInt16 + /// + private const string Type_UShort = "System.UInt16"; + + /// + /// System.Int32 + /// + private const string Type_Int = "System.Int32"; + + /// + /// System.UInt32 + /// + private const string Type_UInt = "System.UInt32"; + + /// + /// System.Int64 + /// + private const string Type_Long = "System.Int64"; + + /// + /// System.UInt64 + /// + private const string Type_ULong = "System.UInt64"; + + /// + /// System.Single + /// + private const string Type_Float = "System.Single"; + + /// + /// System.Double + /// + private const string Type_Double = "System.Double"; + + /// + /// System.Boolean + /// + private const string Type_Bool = "System.Boolean"; + + /// + /// System.Char + /// + private const string Type_Char = "System.Char"; + + /// + /// System.Decimal + /// + private const string Type_Decimal = "System.Decimal"; + + /// + /// System.String + /// + private const string Type_String = "System.String"; + + #endregion } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/IWebSocketHandler.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/IWebSocketHandler.cs index 4fef7de..42bd8d1 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/IWebSocketHandler.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/IWebSocketHandler.cs @@ -2,9 +2,6 @@ using Cyaim.WebSocketServer.Middlewares; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; namespace Cyaim.WebSocketServer.Infrastructure.Handlers @@ -37,7 +34,6 @@ public interface IWebSocketHandler /// /// Task ConnectionEntry(HttpContext context, ILogger logger, WebSocketRouteOption webSocketOptions); - } /// @@ -46,7 +42,7 @@ public interface IWebSocketHandler public class WebSocketHandlerMetadata { /// - /// Describe the function of the handle and how to use it + /// Describe the function of the handle and how to use it /// public string Describe { get; set; } @@ -60,4 +56,4 @@ public class WebSocketHandlerMetadata /// public bool CanHandleText { get; set; } } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs index 09a7bd0..4b1d4f1 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs @@ -9,8 +9,6 @@ using System.IO; using System.Linq; using System.Net.WebSockets; -using System.Reflection; -using System.Runtime.InteropServices.ComTypes; using System.Text; using System.Text.Json; using System.Text.Json.Nodes; @@ -24,12 +22,6 @@ namespace Cyaim.WebSocketServer.Infrastructure.Handlers.MvcHandler /// public class MvcChannelHandler : IWebSocketHandler { - /// - /// Connected clients by mvc channel - /// - public static ConcurrentDictionary Clients { get; set; } = new ConcurrentDictionary(); - - private ILogger logger; private WebSocketRouteOption webSocketOption; @@ -42,15 +34,19 @@ public MvcChannelHandler(int receiveBufferSize = 4 * 1024) ReceiveTextBufferSize = ReceiveBinaryBufferSize = receiveBufferSize; } + /// + /// Connected clients by mvc channel + /// + public static ConcurrentDictionary Clients { get; set; } = new ConcurrentDictionary(); /// /// Metadata used when parsing the handler /// - public WebSocketHandlerMetadata Metadata { get; } = new WebSocketHandlerMetadata() + public WebSocketHandlerMetadata Metadata { get; } = new WebSocketHandlerMetadata { Describe = "Provide MVC forwarding handler", CanHandleBinary = true, - CanHandleText = true, + CanHandleText = true }; /// @@ -73,33 +69,29 @@ public MvcChannelHandler(int receiveBufferSize = 4 * 1024) public async Task ConnectionEntry(HttpContext context, ILogger logger, WebSocketRouteOption webSocketOptions) { this.logger = logger; - this.webSocketOption = webSocketOptions; - + webSocketOption = webSocketOptions; WebSocket webSocketCloseInst = null; - try { if (context.WebSockets.IsWebSocketRequest) { // Event instructions whether connection - bool ifThisContinue = await MvcChannel_OnBeforeConnection(context, webSocketOptions, context.Request.Path, logger); + var ifThisContinue = await MvcChannel_OnBeforeConnection(context, webSocketOptions, context.Request.Path, logger); if (!ifThisContinue) { return; } - bool ifContinue = await webSocketOptions.OnBeforeConnection(context, webSocketOptions, context.Request.Path, logger); + var ifContinue = await webSocketOptions.OnBeforeConnection(context, webSocketOptions, context.Request.Path, logger); if (!ifContinue) { return; } - - using WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); + using var webSocket = await context.WebSockets.AcceptWebSocketAsync(); try { webSocketCloseInst = webSocket; - logger.LogInformation($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Connected({context.Connection.Id})"); - bool succ = Clients.TryAdd(context.Connection.Id, webSocket); + var succ = Clients.TryAdd(context.Connection.Id, webSocket); if (succ) { await MvcForward(context, webSocket); @@ -108,8 +100,6 @@ public async Task ConnectionEntry(HttpContext context, ILogger Connection pool exception({context.Connection.Id}),ConnectionId repeat"); } - - } catch (Exception ex) { @@ -129,124 +119,10 @@ public async Task ConnectionEntry(HttpContext context, ILogger - ///// Forward by WebSocket transfer type - ///// - ///// - ///// - ///// - //private async Task MvcForward(HttpContext context, WebSocket webSocket) - //{ - // var buffer = new byte[ReceiveTextBufferSize]; - // ArraySegment bufferSeg = new ArraySegment(buffer); - - // try - // { - // WebSocketReceiveResult result = await webSocket.ReceiveAsync(bufferSeg, CancellationToken.None); - // //switch (result.MessageType) - // //{ - // // case WebSocketMessageType.Binary: - // // await MvcBinaryForward(context, webSocket, result, buffer); - // // break; - // // case WebSocketMessageType.Text: - // // await MvcTextForward(webSocket, context, result, buffer); - // // break; - // //} - // await MvcForward(webSocket, context, result, bufferSeg); - - // //链接断开 - // await webSocket.CloseAsync(webSocket.CloseStatus == null ? - // webSocket.State == WebSocketState.Aborted ? - // WebSocketCloseStatus.InternalServerError : WebSocketCloseStatus.NormalClosure - // : webSocket.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); - // } - // catch (OperationCanceledException ex) - // { - // logger.LogInformation($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> 终止接收数据({context.Connection.Id})\r\nStatus:{(webSocket.CloseStatus.HasValue ? webSocket.CloseStatus.ToString() : "ServerClose")}\r\n{ex.Message}"); - // } - //} - - ///// - ///// Handle request content - ///// - ///// - ///// - ///// - ///// - ///// - //private async Task MvcForward(WebSocket webSocket, HttpContext context, WebSocketReceiveResult result, ArraySegment buffer) - //{ - - // long requestTime = DateTime.Now.Ticks; - // StringBuilder json = new StringBuilder(); - - // //处理第一次返回的数据 - // json = json.Append(Encoding.UTF8.GetString(buffer[..result.Count])); - - // //第一次接受已经接受完数据了 - // if (result.EndOfMessage) - // { - // try - // { - // await MvcForwardSendData(webSocket, context, result, json, requestTime); - // } - // catch (Exception ex) - // { - // logger.LogError(ex, ex.Message); - // } - // finally - // { - // json = json.Clear(); - // } - // } - - // //等待客户端发送数据,第二次接受数据 - // while (!result.CloseStatus.HasValue) - // { - // try - // { - // if (!(webSocket.State == WebSocketState.Open || webSocket.State == WebSocketState.CloseSent)) - // { - // break; - // } - - // result = await webSocket.ReceiveAsync(buffer, CancellationToken.None); - // requestTime = DateTime.Now.Ticks; - - // json = json.Append(Encoding.UTF8.GetString(buffer[..result.Count])); - - // if (!result.EndOfMessage || result.CloseStatus.HasValue) - // { - // continue; - // } - - // await MvcForwardSendData(webSocket, context, result, json, requestTime); - - // json = json.Clear(); - // } - // catch (OperationCanceledException ex) - // { - // logger.LogInformation($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> 终止接收数据({context.Connection.Id})\r\nStatus:{(webSocket.CloseStatus.HasValue ? webSocket.CloseStatus.ToString() : "ServerClose")}\r\n{ex.Message}"); - // } - // catch (Exception ex) - // { - // logger.LogError(ex, ex.Message); - // } - - // } - - - //} - #endregion - /// /// Forward by WebSocket transfer type /// @@ -257,12 +133,12 @@ private async Task MvcForward(HttpContext context, WebSocket webSocket) { try { - CancellationTokenSource connCts = new CancellationTokenSource(); - string wsCloseDesc = string.Empty; - using MemoryStream wsReceiveReader = new MemoryStream(ReceiveTextBufferSize); + var connCts = new CancellationTokenSource(); + string wsCloseDesc; + using var wsReceiveReader = new MemoryStream(ReceiveTextBufferSize); do { - long requestTime = DateTime.Now.Ticks; + var requestTime = DateTime.Now.Ticks; WebSocketReceiveResult result = null; try { @@ -273,16 +149,13 @@ private async Task MvcForward(HttpContext context, WebSocket webSocket) connCts.Cancel(); goto CONTINUE; } - else - { - await Task.Delay(1000).ConfigureAwait(false); - goto CONTINUE; - } - + await Task.Delay(1000, connCts.Token).ConfigureAwait(false); + goto CONTINUE; } #region 接收数据 - byte[] buffer = ArrayPool.Shared.Rent(ReceiveTextBufferSize); + + var buffer = ArrayPool.Shared.Rent(ReceiveTextBufferSize); while ((result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None)).Count > 0) { try @@ -295,7 +168,7 @@ private async Task MvcForward(HttpContext context, WebSocket webSocket) } //await wsReceiveReader.WriteAsync(buffer, 0, result.Count); - await wsReceiveReader.WriteAsync(buffer.AsMemory(0, result.Count)); + await wsReceiveReader.WriteAsync(buffer.AsMemory(0, result.Count), connCts.Token); // 已经接受完数据了 if (result.EndOfMessage || result.CloseStatus.HasValue) { @@ -311,6 +184,7 @@ private async Task MvcForward(HttpContext context, WebSocket webSocket) ArrayPool.Shared.Return(buffer); } } + #endregion if (result == null) @@ -329,22 +203,20 @@ private async Task MvcForward(HttpContext context, WebSocket webSocket) //JsonDocument document = JsonDocument.Parse(wsReceiveReader.GetBuffer()); MvcRequestScheme requestScheme; JsonObject requestBody; - using (JsonDocument doc = JsonDocument.Parse(wsReceiveReader.GetBuffer())) + using (var doc = JsonDocument.Parse(wsReceiveReader.GetBuffer())) { - JsonElement root = doc.RootElement; - bool hasBody = root.TryGetProperty("Body", out JsonElement body); + var root = doc.RootElement; + var hasBody = root.TryGetProperty("Body", out var body); if (!hasBody) { hasBody = root.TryGetProperty("body", out body); } - - requestScheme = doc.Deserialize(webSocketOption.DefaultRequestJsonSerialiazerOptions); - requestBody = body.ValueKind == JsonValueKind.Undefined ? null : (JsonNode.Parse(body.GetRawText())?.AsObject()); + requestScheme = doc.Deserialize(webSocketOption.DefaultRequestJsonSerializerOptions); + requestBody = body.ValueKind == JsonValueKind.Undefined ? null : JsonNode.Parse(body.GetRawText())?.AsObject(); } //requestScheme = JsonSerializer.Deserialize(wsReceiveReader.GetBuffer(), webSocketOption.DefaultRequestJsonSerialiazerOptions); await MvcForwardSendData(webSocket, context, result, requestScheme, requestBody, requestTime); - CONTINUE:; } catch (Exception ex) @@ -354,16 +226,13 @@ private async Task MvcForward(HttpContext context, WebSocket webSocket) finally { wsCloseDesc = result?.CloseStatusDescription; - - wsReceiveReader.Flush(); + await wsReceiveReader.FlushAsync(connCts.Token); wsReceiveReader.SetLength(0); wsReceiveReader.Seek(0, SeekOrigin.Begin); wsReceiveReader.Position = 0; } - } while (!connCts.IsCancellationRequested); - //switch (result.MessageType) //{ // case WebSocketMessageType.Binary: @@ -377,10 +246,7 @@ private async Task MvcForward(HttpContext context, WebSocket webSocket) // 连接断开 if (webSocket.State == WebSocketState.Open || webSocket.State == WebSocketState.CloseSent) { - await webSocket.CloseAsync(webSocket.CloseStatus == null ? - webSocket.State == WebSocketState.Aborted ? - WebSocketCloseStatus.InternalServerError : WebSocketCloseStatus.NormalClosure - : webSocket.CloseStatus.Value, wsCloseDesc, CancellationToken.None); + await webSocket.CloseAsync(webSocket.CloseStatus ?? (webSocket.State == WebSocketState.Aborted ? WebSocketCloseStatus.InternalServerError : WebSocketCloseStatus.NormalClosure), wsCloseDesc, CancellationToken.None); } } catch (Exception ex) @@ -412,26 +278,19 @@ private async Task MvcForwardSendData(WebSocket webSocket, HttpContext context, object invokeResult = await MvcDistributeAsync(webSocketOption, context, webSocket, request, requestBody, logger); // 发送结果给客户端 - string serialJson = JsonSerializer.Serialize(invokeResult, webSocketOption.DefaultResponseJsonSerialiazerOptions); + var serialJson = JsonSerializer.Serialize(invokeResult, webSocketOption.DefaultResponseJsonSerializerOptions); await webSocket.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes(serialJson)), result.MessageType, result.EndOfMessage, CancellationToken.None); } catch (JsonException ex) { - MvcResponseSchemeException mvcRespEx = new MvcResponseSchemeException($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Request parsing error\r\n {ex.Message}\r\n{ex.StackTrace}") + var mvcRespEx = new MvcResponseSchemeException($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Request parsing error\r\n {ex.Message}\r\n{ex.StackTrace}") { Status = 1, RequestTime = requsetTicks, - ComplateTime = DateTime.Now.Ticks, + CompleteTime = DateTime.Now.Ticks }; logger.LogTrace(mvcRespEx, mvcRespEx.Message); } - catch (Exception) - { - - throw; - } - - } /// @@ -454,8 +313,8 @@ private async Task MvcForwardSendData(WebSocket webSocket, HttpContext context, //按节点请求转发 JsonObject requestBody = null; - string jsonString = JsonSerializer.Serialize(request.Body, webSocketOption.DefaultRequestJsonSerialiazerOptions); - JsonNode requestJsonNode = JsonNode.Parse(jsonString); + var jsonString = JsonSerializer.Serialize(request.Body, webSocketOption.DefaultRequestJsonSerializerOptions); + var requestJsonNode = JsonNode.Parse(jsonString); if (requestJsonNode != null) { requestBody = requestJsonNode.AsObject(); @@ -463,30 +322,21 @@ private async Task MvcForwardSendData(WebSocket webSocket, HttpContext context, object invokeResult = await MvcDistributeAsync(webSocketOption, context, webSocket, request, requestBody, logger); // 发送结果给客户端 - string serialJson = JsonSerializer.Serialize(invokeResult, webSocketOption.DefaultResponseJsonSerialiazerOptions); + var serialJson = JsonSerializer.Serialize(invokeResult, webSocketOption.DefaultResponseJsonSerializerOptions); await webSocket.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes(serialJson)), result.MessageType, result.EndOfMessage, CancellationToken.None); } catch (JsonException ex) { - MvcResponseSchemeException mvcRespEx = new MvcResponseSchemeException($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Request parsing error\r\n {ex.Message}\r\n{ex.StackTrace}") + var mvcRespEx = new MvcResponseSchemeException($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Request parsing error\r\n {ex.Message}\r\n{ex.StackTrace}") { Status = 1, RequestTime = requsetTicks, - ComplateTime = DateTime.Now.Ticks, + CompleteTime = DateTime.Now.Ticks }; logger.LogTrace(mvcRespEx, mvcRespEx.Message); } - catch (Exception) - { - - throw; - } - - } - - /// /// MvcChannel forward data /// @@ -504,87 +354,444 @@ private async Task MvcForwardSendData(WebSocket webSocket, HttpContext context, { return; } - - MvcRequestScheme request = JsonSerializer.Deserialize(json.ToString(), webSocketOption.DefaultRequestJsonSerialiazerOptions); + var request = JsonSerializer.Deserialize(json.ToString(), webSocketOption.DefaultRequestJsonSerializerOptions); if (request == null) { logger.LogTrace($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Request body format error({context.Connection.Id}\r\n{json}"); return; } - await MvcForwardSendData(webSocket, context, result, request, requsetTicks).ConfigureAwait(false); } catch (JsonException ex) { - MvcResponseSchemeException mvcRespEx = new MvcResponseSchemeException($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Request parsing error\r\n {ex.Message}\r\n{ex.StackTrace}") + var mvcRespEx = new MvcResponseSchemeException($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Request parsing error\r\n {ex.Message}\r\n{ex.StackTrace}") { Status = 1, RequestTime = requsetTicks, - ComplateTime = DateTime.Now.Ticks, + CompleteTime = DateTime.Now.Ticks }; logger.LogTrace(mvcRespEx, mvcRespEx.Message); } - catch (Exception) - { - - throw; - } - - } + /// + /// Forward request to endpoint method + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task MvcDistributeAsync(WebSocketRouteOption webSocketOptions, HttpContext context, WebSocket webSocket, MvcRequestScheme request, JsonObject requestBody, ILogger logger) + { + var requestTime = DateTime.Now.Ticks; + var requestPath = request.Target.ToLower(); + try + { + // 从键值对中获取对应的执行函数 + webSocketOptions.WatchAssemblyContext.WatchMethods.TryGetValue(requestPath, out var method); + if (method == null) + { + goto NotFound; + } + var @class = webSocketOptions.WatchAssemblyContext.WatchEndPoint.FirstOrDefault(x => x.MethodPath == requestPath)?.Class; + if (@class == null) + { + //找不到访问目标 + goto NotFound; + } - #region Newtonsoft.Json + #region 注入Socket的HttpContext和WebSocket客户端 - ///// - ///// Forward request to endpoint method - ///// - ///// - ///// - ///// - ///// - ///// - ///// - //public static async Task MvcDistributeAsync(WebSocketRouteOption webSocketOptions, HttpContext context, WebSocket webSocket, MvcRequestScheme request, ILogger logger) - //{ - // long requestTime = DateTime.Now.Ticks; - // string requestPath = request.Target.ToLower(); - // JObject requestBody = request.Body as JObject; - // try - // { - // // 从键值对中获取对应的执行函数 - // webSocketOptions.WatchAssemblyContext.WatchMethods.TryGetValue(requestPath, out MethodInfo method); + var contextInfo = @class.GetProperty(webSocketOptions.InjectionHttpContextPropertyName); + var socketInfo = @class.GetProperty(webSocketOptions.InjectionWebSocketClientPropertyName); + webSocketOptions.WatchAssemblyContext.MaxConstructorParameters.TryGetValue(@class, out var constructorParameter); + var instanceParams = new object[constructorParameter.ParameterInfos.Length]; + // 从Scope从DI容器提取目标类构造函数所需的对象 + var serviceScopeFactory = WebSocketRouteOption.ApplicationServices.GetService(); + var serviceScope = serviceScopeFactory.CreateScope(); + var scopeIocProvider = serviceScope.ServiceProvider; + for (var i = 0; i < constructorParameter.ParameterInfos.Length; i++) + { + var item = constructorParameter.ParameterInfos[i]; + if (webSocketOptions.ApplicationServiceCollection == null) + { + logger.LogWarning("Cannot inject target constructor parameter because DI container WebSocketRouteOption.ApplicationServiceCollection is null."); + break; + } + var nonSingleton = webSocketOptions.ApplicationServiceCollection.FirstOrDefault(x => x.ServiceType == item.ParameterType); + instanceParams[i] = nonSingleton == null || nonSingleton.Lifetime == ServiceLifetime.Singleton + ? WebSocketRouteOption.ApplicationServices.GetService(item.ParameterType) + : scopeIocProvider.GetService(item.ParameterType); + } + var inst = Activator.CreateInstance(@class, instanceParams); - // if (method == null) - // { - // goto NotFound; - // } - // Type clss = webSocketOptions.WatchAssemblyContext.WatchEndPoint.FirstOrDefault(x => x.MethodPath == requestPath)?.Class; - // if (clss == null) - // { - // //找不到访问目标 + // 注入目标类中的帮助属性HttpContext、WebSocket + if (contextInfo != null && contextInfo.CanWrite) + { + contextInfo.SetValue(inst, context); + } + if (socketInfo != null && socketInfo.CanWrite) + { + socketInfo.SetValue(inst, webSocket); + } - // goto NotFound; - // } + #endregion - // #region 注入Socket的HttpContext和WebSocket客户端 - // PropertyInfo contextInfo = clss.GetProperty(webSocketOptions.InjectionHttpContextPropertyName); - // PropertyInfo socketInfo = clss.GetProperty(webSocketOptions.InjectionWebSocketClientPropertyName); + var mvcResponse = new MvcResponseScheme { Status = 0, RequestTime = requestTime }; - // webSocketOptions.WatchAssemblyContext.MaxCoustructorParameters.TryGetValue(clss, out ConstructorParameter constructorParameter); + #region 注入调用方法参数 - // object[] instanceParmas = new object[constructorParameter.ParameterInfos.Length]; - // // Scope - // var serviceScopeFactory = WebSocketRouteOption.ApplicationServices.GetService(); - // var serviceScope = serviceScopeFactory.CreateScope(); - // var scopeIocProvider = serviceScope.ServiceProvider; - // for (int i = 0; i < constructorParameter.ParameterInfos.Length; i++) - // { - // ParameterInfo item = constructorParameter.ParameterInfos[i]; + webSocketOptions.WatchAssemblyContext.MethodParameters.TryGetValue(method, out var methodParam); + object invokeResult; + if (requestBody == null || requestBody.Count <= 0) + { + var args = Array.Empty(); + // 有参方法 + if (methodParam != null && methodParam.Length > 0) + { + args = new object[methodParam.LongLength]; - // if (webSocketOptions.ApplicationServiceCollection == null) - // { - // logger.LogWarning("Cannot inject target constructor parameter because DI container WebSocketRouteOption.ApplicationServiceCollection is null."); + // 为每个参数设置其类型的默认值 + for (var i = 0; i < methodParam.Length; i++) + { + var item = methodParam[i]; + if (item.HasDefaultValue) + { + args[i] = item.DefaultValue; + continue; + } + // 如果参数类型是值类型,则使用类型的零值 + if (item.ParameterType.IsValueType) + { + args[i] = Activator.CreateInstance(item.ParameterType); + } + else + { + // 如果参数类型是引用类型,则使用 null + args[i] = null; + } + } + } + else if (methodParam.Length < 0) + { + throw new InvalidOperationException("请求的目标终结点参数异常"); + } + invokeResult = method.Invoke(inst, args); + } + else + { + // 异步调用目标方法 + var invoke = new Task(() => + { + var methodParm = new object[methodParam.Length]; + for (var i = 0; i < methodParam.Length; i++) + { + var item = methodParam[i]; + + // 检测方法中的参数是否是C#定义的基本类型 + object parmVal = null; + try + { + // 按参数名提取JsonNode + var hasVal = requestBody.TryGetPropertyValue(item.Name, out var JProp); + if (hasVal) + { + parmVal = item.ParameterType.ConvertTo(requestBody[item.Name]); + } + else + { + continue; + } + } + catch (JsonException ex) + { + // 反序列化失败 + logger.LogTrace($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> {requestPath} An exception occurred while operating the request data JSON\r\n{ex.Message}\r\n{ex.StackTrace}"); + } + catch (FormatException ex) + { + // ConvertTo 抛出 类型转换失败 + logger.LogTrace($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> {requestPath} Parameter data formatting exception in the request body\r\n{ex.Message}\r\n{ex.StackTrace}"); + } + methodParm[i] = parmVal; + } + return method.Invoke(inst, methodParm); + }); + invoke.Start(); + invokeResult = await invoke; + } + + // Async api support + if (invokeResult is Task) + { + dynamic invokeResultTask = invokeResult; + await invokeResultTask; + invokeResult = invokeResultTask.Result; + } + + #endregion + + // Dispose ioc scope + serviceScope?.Dispose(); + mvcResponse.Id = request.Id; + mvcResponse.Target = request.Target; + mvcResponse.Body = invokeResult; + mvcResponse.CompleteTime = DateTime.Now.Ticks; + return mvcResponse; + } + catch (Exception ex) + { + var resp = new MvcResponseScheme { Id = request.Id, Status = 1, RequestTime = requestTime, CompleteTime = DateTime.Now.Ticks }; + if (webSocketOptions.IsDevelopment) + { + resp.Msg = $@"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Target:{requestPath}\r\n{ex.Message}\r\n{ex.StackTrace}"; + } + return resp; + } + NotFound: + return new MvcResponseScheme { Id = request.Id, Status = 2, Msg = $@"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Target:{requestPath} not found", RequestTime = requestTime, CompleteTime = DateTime.Now.Ticks }; + } + + /// + /// Client close connection + /// + /// + /// + /// + /// + private async Task MvcChannel_OnDisconnected(HttpContext context, WebSocket webSocket, WebSocketRouteOption webSocketOptions, ILogger logger) + { + var msg = string.Empty; + if (webSocket?.CloseStatus.HasValue ?? false) + { + msg = webSocket.CloseStatus.Value switch + { + WebSocketCloseStatus.Empty => "No error specified.", + WebSocketCloseStatus.EndpointUnavailable => "Indicates an endpoint is being removed. Either the server or client will become unavailable.", + WebSocketCloseStatus.InternalServerError => "The connection will be closed by the server because of an error on the server.", + WebSocketCloseStatus.InvalidMessageType => "The client or server is terminating the connection because it cannot accept the data type it received.", + WebSocketCloseStatus.InvalidPayloadData => "The client or server is terminating the connection because it has received data inconsistent with the message type.", + WebSocketCloseStatus.MandatoryExtension => "The client is terminating the connection because it expected the server to negotiate an extension.", + WebSocketCloseStatus.MessageTooBig => "Reserved for future use.", + WebSocketCloseStatus.NormalClosure => "The connection has closed after the request was fulfilled.", + WebSocketCloseStatus.PolicyViolation => "The connection will be closed because an endpoint has received a message that violates its policy.", + WebSocketCloseStatus.ProtocolError => "The client or server is terminating the connection because of a protocol error.", + _ => msg + }; + } + else + { + msg = "The connection of this client is shutting down."; + } + logger.LogInformation($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Disconnected({context.Connection.Id})\r\nStatus:{webSocket?.CloseStatus.ToString() ?? "NoHandshakeSucceeded"}\r\n{msg}"); + try + { + await MvcChannel_OnDisConnected(context, webSocketOptions, context.Request.Path, logger); + await webSocketOptions.OnDisConnected(context, webSocketOptions, context.Request.Path, logger); + } + catch (Exception ex) + { + logger.LogInformation(ex, ex.Message); + } + finally + { + var wsExists = Clients.ContainsKey(context.Connection.Id); + if (wsExists) + { + Clients.TryRemove(context.Connection.Id, out var _); + } + } + } + + /// + /// Mvc channel before connection + /// + /// + /// + /// + /// + /// + public virtual async Task MvcChannel_OnBeforeConnection(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) => await Task.FromResult(true); + + /// + /// Mvc channel DisConnectedEvent entry + /// + /// + /// + /// + /// + /// + public virtual async Task MvcChannel_OnDisConnected(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) + { + await Task.CompletedTask; + } + + #region Old + + ///// + ///// Forward by WebSocket transfer type + ///// + ///// + ///// + ///// + //private async Task MvcForward(HttpContext context, WebSocket webSocket) + //{ + // var buffer = new byte[ReceiveTextBufferSize]; + // ArraySegment bufferSeg = new ArraySegment(buffer); + + // try + // { + // WebSocketReceiveResult result = await webSocket.ReceiveAsync(bufferSeg, CancellationToken.None); + // //switch (result.MessageType) + // //{ + // // case WebSocketMessageType.Binary: + // // await MvcBinaryForward(context, webSocket, result, buffer); + // // break; + // // case WebSocketMessageType.Text: + // // await MvcTextForward(webSocket, context, result, buffer); + // // break; + // //} + // await MvcForward(webSocket, context, result, bufferSeg); + + // //链接断开 + // await webSocket.CloseAsync(webSocket.CloseStatus == null ? + // webSocket.State == WebSocketState.Aborted ? + // WebSocketCloseStatus.InternalServerError : WebSocketCloseStatus.NormalClosure + // : webSocket.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + // } + // catch (OperationCanceledException ex) + // { + // logger.LogInformation($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> 终止接收数据({context.Connection.Id})\r\nStatus:{(webSocket.CloseStatus.HasValue ? webSocket.CloseStatus.ToString() : "ServerClose")}\r\n{ex.Message}"); + // } + //} + + ///// + ///// Handle request content + ///// + ///// + ///// + ///// + ///// + ///// + //private async Task MvcForward(WebSocket webSocket, HttpContext context, WebSocketReceiveResult result, ArraySegment buffer) + //{ + + // long requestTime = DateTime.Now.Ticks; + // StringBuilder json = new StringBuilder(); + + // //处理第一次返回的数据 + // json = json.Append(Encoding.UTF8.GetString(buffer[..result.Count])); + + // //第一次接受已经接受完数据了 + // if (result.EndOfMessage) + // { + // try + // { + // await MvcForwardSendData(webSocket, context, result, json, requestTime); + // } + // catch (Exception ex) + // { + // logger.LogError(ex, ex.Message); + // } + // finally + // { + // json = json.Clear(); + // } + // } + + // //等待客户端发送数据,第二次接受数据 + // while (!result.CloseStatus.HasValue) + // { + // try + // { + // if (!(webSocket.State == WebSocketState.Open || webSocket.State == WebSocketState.CloseSent)) + // { + // break; + // } + + // result = await webSocket.ReceiveAsync(buffer, CancellationToken.None); + // requestTime = DateTime.Now.Ticks; + + // json = json.Append(Encoding.UTF8.GetString(buffer[..result.Count])); + + // if (!result.EndOfMessage || result.CloseStatus.HasValue) + // { + // continue; + // } + + // await MvcForwardSendData(webSocket, context, result, json, requestTime); + + // json = json.Clear(); + // } + // catch (OperationCanceledException ex) + // { + // logger.LogInformation($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> 终止接收数据({context.Connection.Id})\r\nStatus:{(webSocket.CloseStatus.HasValue ? webSocket.CloseStatus.ToString() : "ServerClose")}\r\n{ex.Message}"); + // } + // catch (Exception ex) + // { + // logger.LogError(ex, ex.Message); + // } + + // } + + //} + + #endregion + + #region Newtonsoft.Json + + ///// + ///// Forward request to endpoint method + ///// + ///// + ///// + ///// + ///// + ///// + ///// + //public static async Task MvcDistributeAsync(WebSocketRouteOption webSocketOptions, HttpContext context, WebSocket webSocket, MvcRequestScheme request, ILogger logger) + //{ + // long requestTime = DateTime.Now.Ticks; + // string requestPath = request.Target.ToLower(); + // JObject requestBody = request.Body as JObject; + // try + // { + // // 从键值对中获取对应的执行函数 + // webSocketOptions.WatchAssemblyContext.WatchMethods.TryGetValue(requestPath, out MethodInfo method); + + // if (method == null) + // { + // goto NotFound; + // } + // Type clss = webSocketOptions.WatchAssemblyContext.WatchEndPoint.FirstOrDefault(x => x.MethodPath == requestPath)?.Class; + // if (clss == null) + // { + // //找不到访问目标 + + // goto NotFound; + // } + + // #region 注入Socket的HttpContext和WebSocket客户端 + // PropertyInfo contextInfo = clss.GetProperty(webSocketOptions.InjectionHttpContextPropertyName); + // PropertyInfo socketInfo = clss.GetProperty(webSocketOptions.InjectionWebSocketClientPropertyName); + + // webSocketOptions.WatchAssemblyContext.MaxCoustructorParameters.TryGetValue(clss, out ConstructorParameter constructorParameter); + + // object[] instanceParmas = new object[constructorParameter.ParameterInfos.Length]; + // // Scope + // var serviceScopeFactory = WebSocketRouteOption.ApplicationServices.GetService(); + // var serviceScope = serviceScopeFactory.CreateScope(); + // var scopeIocProvider = serviceScope.ServiceProvider; + // for (int i = 0; i < constructorParameter.ParameterInfos.Length; i++) + // { + // ParameterInfo item = constructorParameter.ParameterInfos[i]; + + // if (webSocketOptions.ApplicationServiceCollection == null) + // { + // logger.LogWarning("Cannot inject target constructor parameter because DI container WebSocketRouteOption.ApplicationServiceCollection is null."); // break; // } @@ -763,306 +970,7 @@ private async Task MvcForwardSendData(WebSocket webSocket, HttpContext context, //NotFound: return new MvcResponseScheme() { Id = request.Id, Status = 2, Msg = $@"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Target:{requestPath} not found", RequestTime = requestTime, ComplateTime = DateTime.Now.Ticks }; //} - #endregion - - /// - /// Forward request to endpoint method - /// - /// - /// - /// - /// - /// - /// - /// - public static async Task MvcDistributeAsync(WebSocketRouteOption webSocketOptions, HttpContext context, WebSocket webSocket, MvcRequestScheme request, JsonObject requestBody, ILogger logger) - { - long requestTime = DateTime.Now.Ticks; - string requestPath = request.Target.ToLower(); - - try - { - // 从键值对中获取对应的执行函数 - webSocketOptions.WatchAssemblyContext.WatchMethods.TryGetValue(requestPath, out MethodInfo method); - - if (method == null) - { - goto NotFound; - } - Type clss = webSocketOptions.WatchAssemblyContext.WatchEndPoint.FirstOrDefault(x => x.MethodPath == requestPath)?.Class; - if (clss == null) - { - //找不到访问目标 - goto NotFound; - } - - #region 注入Socket的HttpContext和WebSocket客户端 - PropertyInfo contextInfo = clss.GetProperty(webSocketOptions.InjectionHttpContextPropertyName); - PropertyInfo socketInfo = clss.GetProperty(webSocketOptions.InjectionWebSocketClientPropertyName); - - webSocketOptions.WatchAssemblyContext.MaxCoustructorParameters.TryGetValue(clss, out ConstructorParameter constructorParameter); - - object[] instanceParmas = new object[constructorParameter.ParameterInfos.Length]; - // 从Scope从DI容器提取目标类构造函数所需的对象 - var serviceScopeFactory = WebSocketRouteOption.ApplicationServices.GetService(); - var serviceScope = serviceScopeFactory.CreateScope(); - var scopeIocProvider = serviceScope.ServiceProvider; - for (int i = 0; i < constructorParameter.ParameterInfos.Length; i++) - { - ParameterInfo item = constructorParameter.ParameterInfos[i]; - - if (webSocketOptions.ApplicationServiceCollection == null) - { - logger.LogWarning("Cannot inject target constructor parameter because DI container WebSocketRouteOption.ApplicationServiceCollection is null."); - break; - } - - ServiceDescriptor nonSingleton = webSocketOptions.ApplicationServiceCollection.FirstOrDefault(x => x.ServiceType == item.ParameterType); - if (nonSingleton == null || nonSingleton.Lifetime == ServiceLifetime.Singleton) - { - instanceParmas[i] = WebSocketRouteOption.ApplicationServices.GetService(item.ParameterType); - } - else - { - instanceParmas[i] = scopeIocProvider.GetService(item.ParameterType); - } - } - - object inst = Activator.CreateInstance(clss, instanceParmas); - - // 注入目标类中的帮助属性HttpContext、WebSocket - if (contextInfo != null && contextInfo.CanWrite) - { - contextInfo.SetValue(inst, context); - } - if (socketInfo != null && socketInfo.CanWrite) - { - socketInfo.SetValue(inst, webSocket); - } - #endregion - - MvcResponseScheme mvcResponse = new MvcResponseScheme() { Status = 0, RequestTime = requestTime }; - #region 注入调用方法参数 - webSocketOptions.WatchAssemblyContext.MethodParameters.TryGetValue(method, out ParameterInfo[] methodParam); - - object invokeResult = default; - if (requestBody == null || requestBody.Count <= 0) - { - object[] args = Array.Empty(); - // 有参方法 - if (methodParam.Length > 0) - { - args = new object[methodParam.LongLength]; - - // 为每个参数设置其类型的默认值 - for (int i = 0; i < methodParam.Length; i++) - { - ParameterInfo item = methodParam[i]; - if (item.HasDefaultValue) - { - args[i] = item.DefaultValue; - continue; - } - // 如果参数类型是值类型,则使用类型的零值 - if (item.ParameterType.IsValueType) - { - args[i] = Activator.CreateInstance(item.ParameterType); - } - else - { - // 如果参数类型是引用类型,则使用 null - args[i] = null; - } - } - } - else if (methodParam.Length < 0) - { - throw new InvalidOperationException("请求的目标终结点参数异常"); - } - invokeResult = method.Invoke(inst, args); - } - else - { - // 异步调用目标方法 - Task invoke = new Task(() => - { - object[] methodParm = new object[methodParam.Length]; - for (int i = 0; i < methodParam.Length; i++) - { - ParameterInfo item = methodParam[i]; - - // 检测方法中的参数是否是C#定义的基本类型 - object parmVal = null; - try - { - // 按参数名提取JsonNode - bool hasVal = requestBody.TryGetPropertyValue(item.Name, out JsonNode JProp); - if (hasVal) - { - parmVal = item.ParameterType.ConvertTo(requestBody[item.Name]); - } - else - { - continue; - } - } - catch (JsonException ex) - { - // 反序列化失败 - logger.LogTrace($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> {requestPath} An exception occurred while operating the request data JSON\r\n{ex.Message}\r\n{ex.StackTrace}"); - } - catch (FormatException ex) - { - // ConvertTo 抛出 类型转换失败 - logger.LogTrace($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> {requestPath} Parameter data formatting exception in the request body\r\n{ex.Message}\r\n{ex.StackTrace}"); - } - methodParm[i] = parmVal; - } - - return method.Invoke(inst, methodParm); - }); - invoke.Start(); - - invokeResult = await invoke; - } - - // Async api support - if (invokeResult is Task) - { - dynamic invokeResultTask = invokeResult; - await invokeResultTask; - - invokeResult = invokeResultTask.Result; - } - #endregion - - // Dispose ioc scope - serviceScope?.Dispose(); - serviceScope = null; - - mvcResponse.Id = request.Id; - mvcResponse.Target = request.Target; - mvcResponse.Body = invokeResult; - mvcResponse.ComplateTime = DateTime.Now.Ticks; - - return mvcResponse; - - } - catch (Exception ex) - { - var resp = new MvcResponseScheme() { Id = request.Id, Status = 1, RequestTime = requestTime, ComplateTime = DateTime.Now.Ticks }; - if (webSocketOptions.IsDevelopment) - { - resp.Msg = $@"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Target:{requestPath}\r\n{ex.Message}\r\n{ex.StackTrace}"; - } - return resp; - } - - NotFound: return new MvcResponseScheme() { Id = request.Id, Status = 2, Msg = $@"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Target:{requestPath} not found", RequestTime = requestTime, ComplateTime = DateTime.Now.Ticks }; - } - - /// - /// Client close connection - /// - /// - /// - /// - /// - private async Task MvcChannel_OnDisconnected(HttpContext context, WebSocket webSocket, WebSocketRouteOption webSocketOptions, ILogger logger) - { - string msg = string.Empty; - - if (webSocket?.CloseStatus.HasValue ?? false) - { - switch (webSocket.CloseStatus.Value) - { - case WebSocketCloseStatus.Empty: - msg = "No error specified."; - break; - case WebSocketCloseStatus.EndpointUnavailable: - msg = "Indicates an endpoint is being removed. Either the server or client will become unavailable."; - break; - case WebSocketCloseStatus.InternalServerError: - msg = "The connection will be closed by the server because of an error on the server."; - break; - case WebSocketCloseStatus.InvalidMessageType: - msg = "The client or server is terminating the connection because it cannot accept the data type it received."; - break; - case WebSocketCloseStatus.InvalidPayloadData: - msg = "The client or server is terminating the connection because it has received data inconsistent with the message type."; - break; - case WebSocketCloseStatus.MandatoryExtension: - msg = "The client is terminating the connection because it expected the server to negotiate an extension."; - break; - case WebSocketCloseStatus.MessageTooBig: - msg = "Reserved for future use."; - break; - case WebSocketCloseStatus.NormalClosure: - msg = "The connection has closed after the request was fulfilled."; - break; - case WebSocketCloseStatus.PolicyViolation: - msg = "The connection will be closed because an endpoint has received a messagethat violates its policy."; - break; - case WebSocketCloseStatus.ProtocolError: - msg = "The client or server is terminating the connection because of a protocol error."; - break; - default: - break; - } - } - else - { - msg = "The connection of this client is shutting down."; - } - - logger.LogInformation($"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort} -> Disconnected({context.Connection.Id})\r\nStatus:{webSocket?.CloseStatus.ToString() ?? "NoHandshakeSucceeded"}\r\n{msg}"); - - try - { - await MvcChannel_OnDisConnectioned(context, webSocketOptions, context.Request.Path, logger); - - await webSocketOptions.OnDisConnectioned(context, webSocketOptions, context.Request.Path, logger); - } - catch (Exception ex) - { - logger.LogInformation(ex, ex.Message); - } - finally - { - bool wsExists = Clients.ContainsKey(context.Connection.Id); - if (wsExists) - { - Clients.TryRemove(context.Connection.Id, out var _); - } - } - } - - /// - /// Mvc channel before connection - /// - /// - /// - /// - /// - /// - public virtual async Task MvcChannel_OnBeforeConnection(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) - { - return await Task.FromResult(true); - } - - /// - /// Mvc channel DisConnectionedEvent entry - /// - /// - /// - /// - /// - /// - public virtual async Task MvcChannel_OnDisConnectioned(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) - { - await Task.CompletedTask; - } - + #endregion } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcResponseScheme.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcResponseScheme.cs index 00e3681..0335c34 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcResponseScheme.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcResponseScheme.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Runtime.Serialization; -using System.Text; namespace Cyaim.WebSocketServer.Infrastructure.Handlers.MvcHandler { @@ -10,16 +7,6 @@ namespace Cyaim.WebSocketServer.Infrastructure.Handlers.MvcHandler /// public class MvcResponseScheme : IMvcScheme { - /// - /// Response Id with request consistent - /// - public string Id { get; set; } - - /// - /// Target when responding to return requests - /// - public string Target { get; set; } - /// /// Response status. /// Success:0,Application Error:1,NotFoundTarget:2 @@ -37,15 +24,24 @@ public class MvcResponseScheme : IMvcScheme public long RequestTime { get; set; } /// - /// Handle complate time tick + /// Handle complete time tick + /// + public long CompleteTime { get; set; } + + /// + /// Response Id with request consistent + /// + public string Id { get; set; } + + /// + /// Target when responding to return requests /// - public long ComplateTime { get; set; } + public string Target { get; set; } /// /// Response body /// public object Body { get; set; } - } /// @@ -56,9 +52,7 @@ public class MvcResponseSchemeException : Exception /// /// MvcResponseSchemeException /// - public MvcResponseSchemeException() - { - } + public MvcResponseSchemeException() { } /// /// MvcResponseSchemeException @@ -79,14 +73,13 @@ public MvcResponseSchemeException(string message, Exception innerException) : ba Msg = message; } - /// - /// Response Id with request consistent + /// Response Id with request consistent /// public string Id { get; set; } /// - /// Target when responding to return requests + /// Target when responding to return requests /// public string Target { get; set; } @@ -107,8 +100,8 @@ public MvcResponseSchemeException(string message, Exception innerException) : ba public long RequestTime { get; set; } /// - /// Handle complate time tick + /// Handle complete time tick /// - public long ComplateTime { get; set; } + public long CompleteTime { get; set; } } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/WebSocketManager.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/WebSocketManager.cs index b0ff5ca..02ef7fa 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/WebSocketManager.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/WebSocketManager.cs @@ -16,15 +16,16 @@ public static class WebSocketManager /// /// Default send encoding /// - public static Encoding Encoding { get; set; } = Encoding.UTF8; + private static Encoding Encoding { get; } = Encoding.UTF8; + /// - /// JsonSerialiazerOptions + /// JsonSerializerOptions /// - public static JsonSerializerOptions DefaultMvcJsonSerialiazerOptions { get; set; } = new JsonSerializerOptions + private static JsonSerializerOptions DefaultMvcJsonSerializerOptions { get; } = new JsonSerializerOptions { // 设置为 true 以忽略属性名称的大小写 PropertyNameCaseInsensitive = true, - WriteIndented = false, + WriteIndented = false }; /// @@ -42,7 +43,7 @@ public static async Task SendAsync(MemoryStream buffer, WebSocketMessageType mes { return; } - ParallelLoopResult result = Parallel.ForEach(socket, async (s, state) => + var result = Parallel.ForEach(socket, async (s, state) => { try { @@ -60,10 +61,8 @@ public static async Task SendAsync(MemoryStream buffer, WebSocketMessageType mes // await webSocket.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None); // sent += length; //} - await s.SendAsync(buffer.GetBuffer(), messageType, endOfMessage, cancellationToken); } - } catch (AggregateException age) { @@ -72,18 +71,11 @@ public static async Task SendAsync(MemoryStream buffer, WebSocketMessageType mes Console.WriteLine(item.Message); } } - catch (Exception) - { - - throw; - } }); - while (!result.IsCompleted) { - await Task.Delay(TimeSpan.FromSeconds(10)); + await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); } - } /// @@ -101,7 +93,7 @@ public static async Task SendAsync(ReadOnlyMemory buffer, WebSocketMessage { return; } - ParallelLoopResult result = Parallel.ForEach(socket, async (s, state) => + var result = Parallel.ForEach(socket, async (s, state) => { try { @@ -114,7 +106,6 @@ public static async Task SendAsync(ReadOnlyMemory buffer, WebSocketMessage { await s.SendAsync(buffer, messageType, endOfMessage, cancellationToken); } - } catch (AggregateException age) { @@ -123,18 +114,11 @@ public static async Task SendAsync(ReadOnlyMemory buffer, WebSocketMessage Console.WriteLine(item.Message); } } - catch (Exception) - { - - throw; - } }); - while (!result.IsCompleted) { - await Task.Delay(TimeSpan.FromSeconds(10)); + await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); } - } /// @@ -155,7 +139,6 @@ public static async Task SendAsync(string data, WebSocketMessageType messageType await SendAsync(encoding.GetBytes(data), messageType, true, CancellationToken.None, socket); } - /// /// Sending serialized model text data without using a buffer /// @@ -166,20 +149,11 @@ public static async Task SendAsync(string data, WebSocketMessageType messageType /// public static async Task SendAsync(this T data, WebSocketMessageType messageType = WebSocketMessageType.Text, params WebSocket[] socket) { - try + if (data == null || socket == null || socket.LongLength < 1) { - if (data == null || socket == null || socket.LongLength < 1) - { - return; - } - - await SendAsync(JsonSerializer.Serialize(data, DefaultMvcJsonSerialiazerOptions), messageType, Encoding, socket); - } - catch (Exception) - { - - throw; + return; } + await SendAsync(JsonSerializer.Serialize(data, DefaultMvcJsonSerializerOptions), messageType, Encoding, socket); } /// @@ -192,22 +166,11 @@ public static async Task SendAsync(this T data, WebSocketMessageType messageT /// public static async Task SendAsync(this WebSocket socket, T data, WebSocketMessageType messageType = WebSocketMessageType.Text) { - try + if (data == null || socket == null) { - if (data == null || socket == null) - { - return; - } - - await SendAsync(JsonSerializer.Serialize(data, DefaultMvcJsonSerialiazerOptions), messageType, Encoding, socket); - } - catch (Exception) - { - - throw; + return; } + await SendAsync(JsonSerializer.Serialize(data, DefaultMvcJsonSerializerOptions), messageType, Encoding, socket); } - - } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/WebSocketRouteServiceCollectionExtensions.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/WebSocketRouteServiceCollectionExtensions.cs index d68cc59..9c1a5a7 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/WebSocketRouteServiceCollectionExtensions.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/WebSocketRouteServiceCollectionExtensions.cs @@ -1,17 +1,12 @@ using Cyaim.WebSocketServer.Infrastructure.Attributes; using Cyaim.WebSocketServer.Infrastructure.Configures; -using Microsoft.AspNetCore.Hosting.Server.Features; -using Microsoft.AspNetCore.Hosting.Server; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Reflection; -using System.Security.Authentication.ExtendedProtection; -using System.Text; -using System.Globalization; namespace Cyaim.WebSocketServer.Infrastructure { @@ -27,35 +22,25 @@ public static class WebSocketRouteServiceCollectionExtensions /// public static void ConfigureWebSocketRoute(this IServiceCollection services, Action setupAction) { - if (services == null) { throw new ArgumentNullException(nameof(services)); } - if (setupAction == null) { throw new ArgumentNullException(nameof(setupAction)); } - - WebSocketRouteOption wsrOptions = new WebSocketRouteOption(); + var wsrOptions = new WebSocketRouteOption(); setupAction(wsrOptions); - if (wsrOptions == null) - { - wsrOptions = new WebSocketRouteOption(); - } - if (wsrOptions.ApplicationServiceCollection == null) { - throw new ArgumentNullException("WebSocketRouteOption.ApplicationServiceCollection parameter is required and cannot be null."); + throw new ArgumentNullException(nameof(wsrOptions.ApplicationServiceCollection), "WebSocketRouteOption.ApplicationServiceCollection parameter is required and cannot be null."); } - if (wsrOptions.WebSocketChannels == null || wsrOptions.WebSocketChannels.Count < 1) { Console.WriteLine("WebSocket -> 没有定义WebSocket数据处理通道"); } - - Assembly assembly = null; + Assembly assembly; // 指定标记WebSocket特性的程序集路径,默认为本程序集 if (string.IsNullOrEmpty(wsrOptions?.WatchAssemblyPath)) { @@ -66,7 +51,6 @@ public static void ConfigureWebSocketRoute(this IServiceCollection services, Act { assembly = Assembly.LoadFile(wsrOptions.WatchAssemblyPath); } - if (wsrOptions.WatchAssemblyContext == null) { wsrOptions.WatchAssemblyContext = new WatchAssemblyContext(); @@ -74,101 +58,85 @@ public static void ConfigureWebSocketRoute(this IServiceCollection services, Act #region 计算WebSocketEndPoint - List points = new List(); + var points = new List(); // 在程序集中查询带有指定命名空间前缀的类 - string assemblyName = string.IsNullOrEmpty(wsrOptions.WatchAssemblyNamespacePrefix) ? assembly.FullName.Split()[0]?.Trim(',') + ".Controllers" : wsrOptions.WatchAssemblyNamespacePrefix; + var assemblyName = string.IsNullOrEmpty(wsrOptions.WatchAssemblyNamespacePrefix) ? assembly.FullName.Split()[0]?.Trim(',') + ".Controllers" : wsrOptions.WatchAssemblyNamespacePrefix; var types = assembly.GetTypes().Where(x => !x.IsNestedPrivate && x.FullName.StartsWith(assemblyName)).ToList(); - wsrOptions.WatchAssemblyContext.WatchAssemblyPath = wsrOptions.WatchAssemblyPath; wsrOptions.WatchAssemblyContext.WatchAssemblyTypes = types; - - foreach (Type item in types) + foreach (var item in types) { // 从类提取标记了的方法 - var accessParm = GetClassAccessParm(item); - foreach (WebSocketEndPoint parmItem in accessParm) + var accessParam = GetClassAccessParam(item); + foreach (var paramItem in accessParam) { - if (parmItem == null) + if (paramItem == null) { continue; } - - if (string.IsNullOrEmpty(parmItem.Methods.FirstOrDefault())) + if (string.IsNullOrEmpty(paramItem.Methods.FirstOrDefault())) { - parmItem.Methods = new string[] { parmItem.Action }; + paramItem.Methods = new[] { paramItem.Action }; } // 方法的类名替换Controller - string endPointPath = $"{parmItem.Controller.Replace("Controller", string.Empty)}.{parmItem.Methods.FirstOrDefault()}"; + var endPointPath = $"{paramItem.Controller.Replace("Controller", string.Empty)}.{paramItem.Methods.FirstOrDefault()}"; // 终结点全部小写 - parmItem.MethodPath = endPointPath.ToLower(); - parmItem.Class = item; + paramItem.MethodPath = endPointPath.ToLower(); + paramItem.Class = item; Console.WriteLine($"WebSocket加载成功 -> {endPointPath}"); } - - points.AddRange(accessParm); + points.AddRange(accessParam); } - wsrOptions.WatchAssemblyContext.WatchEndPoint = points.ToArray(); - - wsrOptions.WatchAssemblyContext.WatchMethods = - new ConcurrentDictionary( - wsrOptions.WatchAssemblyContext.WatchEndPoint.ToDictionary(x => x.MethodPath, x => x.MethodInfo)); + new ConcurrentDictionary(wsrOptions.WatchAssemblyContext.WatchEndPoint.ToDictionary(x => x.MethodPath, x => x.MethodInfo)); + #endregion #region 计算构造函数与构造函数中的参数 - Dictionary assConstr = new Dictionary(); - Dictionary assConstrParm = new Dictionary(); - - foreach (Type item in wsrOptions.WatchAssemblyContext.WatchAssemblyTypes) + var assConstr = new Dictionary(); + var assConstrParm = new Dictionary(); + foreach (var item in wsrOptions.WatchAssemblyContext.WatchAssemblyTypes) { - ConstructorInfo[] constructorInfos = item.GetConstructors(BindingFlags.Public | BindingFlags.Instance); - List constructorParameters = new List(); - foreach (var constrItem in constructorInfos) + var constructorInfos = item.GetConstructors(BindingFlags.Public | BindingFlags.Instance); + assConstrParm.Add(item, constructorInfos.Select(constrItem => new ConstructorParameter { - ConstructorParameter constructorParameter = new ConstructorParameter(); - - constructorParameter.ConstructorInfo = constrItem; - constructorParameter.ParameterInfos = constrItem.GetParameters(); - - constructorParameters.Add(constructorParameter); - } - - assConstrParm.Add(item, constructorParameters.ToArray()); - + ConstructorInfo = constrItem, + ParameterInfos = constrItem.GetParameters() + }).ToArray()); assConstr.Add(item, constructorInfos); } wsrOptions.WatchAssemblyContext.AssemblyConstructors = assConstr; - wsrOptions.WatchAssemblyContext.CoustructorParameters = assConstrParm; + wsrOptions.WatchAssemblyContext.ConstructorParameters = assConstrParm; + #endregion #region 计算构造函数里参数最多的 - Dictionary maxAssConstrParm = new Dictionary(); + var maxAssConstrParm = new Dictionary(); foreach (var item in assConstrParm) { var pg = item.Value.GroupBy(x => x.ParameterInfos.Length); - - int maxKey = pg.Select(x => x.Key).Max(); - + var maxKey = pg.Select(x => x.Key).Max(); var temp = pg.FirstOrDefault(x => x.Key == maxKey).FirstOrDefault(); maxAssConstrParm.Add(item.Key, temp); } - wsrOptions.WatchAssemblyContext.MaxCoustructorParameters = maxAssConstrParm; + wsrOptions.WatchAssemblyContext.MaxConstructorParameters = maxAssConstrParm; + #endregion #region 计算类公开方法的参数 - Dictionary methodPamams = new Dictionary(); + var methodPamams = new Dictionary(); foreach (var item in points.Select(x => x.MethodInfo)) { - ParameterInfo[] parameterInfo = item.GetParameters(); - + var parameterInfo = item.GetParameters(); methodPamams.Add(item, parameterInfo); } wsrOptions.WatchAssemblyContext.MethodParameters = methodPamams; + #endregion services.AddSingleton(x => wsrOptions); @@ -180,19 +148,18 @@ public static void ConfigureWebSocketRoute(this IServiceCollection services, Act } // 获取当前线程的默认文化 - CultureInfo defaultCultureInfo = CultureInfo.CurrentCulture; + var defaultCultureInfo = CultureInfo.CurrentCulture; } - /// /// Get assembly controller "WebSocket" EndPoint /// /// /// - public static WebSocketEndPoint[] GetClassAccessParm() + public static WebSocketEndPoint[] GetClassAccessParam() { var type = typeof(T); - return GetClassAccessParm(type); + return GetClassAccessParam(type); } /// @@ -200,33 +167,25 @@ public static WebSocketEndPoint[] GetClassAccessParm() /// /// /// - public static WebSocketEndPoint[] GetClassAccessParm(Type type) + public static WebSocketEndPoint[] GetClassAccessParam(Type type) { var methodLevel = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) - .Select(x => - { - return x.GetCustomAttributes().Select(a => - { - WebSocketEndPoint point = new WebSocketEndPoint(); - point.Action = x.Name; - point.Controller = x.ReflectedType.Name; - point.Methods = new string[] { a.Method }; - point.MethodInfo = x; - - return point; - }).ToArray(); - }).SelectMany((x, y) => x); - IEnumerable points = + .Select(x => x.GetCustomAttributes().Select(a => + new WebSocketEndPoint + { + Action = x.Name, + Controller = x.ReflectedType?.Name, + Methods = new[] { a.Method }, + MethodInfo = x + })).SelectMany((x, y) => x); + var points = methodLevel.GroupBy(x => x.Controller + x.Action).Select(x => - { - WebSocketEndPoint first = x.FirstOrDefault(); - - first.Methods = x.Select(m => m.Methods).SelectMany((y, z) => y).Distinct().ToArray(); - - return first; - }); - + { + var first = x.FirstOrDefault(); + first.Methods = x.Select(m => m.Methods).SelectMany((y, z) => y).Distinct().ToArray(); + return first; + }); return points.ToArray(); } } -} +} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net6.0/Cyaim.WebSocketServer.deps.json b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net6.0/Cyaim.WebSocketServer.deps.json deleted file mode 100644 index 807034c..0000000 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net6.0/Cyaim.WebSocketServer.deps.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "runtimeTarget": { - "name": ".NETCoreApp,Version=v6.0", - "signature": "" - }, - "compilationOptions": {}, - "targets": { - ".NETCoreApp,Version=v6.0": { - "Cyaim.WebSocketServer/1.6.3": { - "dependencies": { - "System.Text.Json": "8.0.3" - }, - "runtime": { - "Cyaim.WebSocketServer.dll": {} - } - }, - "System.Runtime.CompilerServices.Unsafe/6.0.0": {}, - "System.Text.Encodings.Web/8.0.0": { - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - }, - "runtime": { - "lib/net6.0/System.Text.Encodings.Web.dll": { - "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.23.53103" - } - }, - "runtimeTargets": { - "runtimes/browser/lib/net6.0/System.Text.Encodings.Web.dll": { - "rid": "browser", - "assetType": "runtime", - "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.23.53103" - } - } - }, - "System.Text.Json/8.0.3": { - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encodings.Web": "8.0.0" - }, - "runtime": { - "lib/net6.0/System.Text.Json.dll": { - "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.324.11423" - } - } - } - } - }, - "libraries": { - "Cyaim.WebSocketServer/1.6.3": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "System.Runtime.CompilerServices.Unsafe/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==", - "path": "system.runtime.compilerservices.unsafe/6.0.0", - "hashPath": "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512" - }, - "System.Text.Encodings.Web/8.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", - "path": "system.text.encodings.web/8.0.0", - "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" - }, - "System.Text.Json/8.0.3": { - "type": "package", - "serviceable": true, - "sha512": "sha512-hpagS9joOwv6efWfrMmV9MjQXpiXZH72PgN067Ysfr6AWMSD1/1hEcvh/U5mUpPLezEWsOJSuVrmqDIVD958iA==", - "path": "system.text.json/8.0.3", - "hashPath": "system.text.json.8.0.3.nupkg.sha512" - } - } -} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net7.0/Cyaim.WebSocketServer.deps.json b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net7.0/Cyaim.WebSocketServer.deps.json deleted file mode 100644 index c0155d8..0000000 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net7.0/Cyaim.WebSocketServer.deps.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "runtimeTarget": { - "name": ".NETCoreApp,Version=v7.0", - "signature": "" - }, - "compilationOptions": {}, - "targets": { - ".NETCoreApp,Version=v7.0": { - "Cyaim.WebSocketServer/1.6.3": { - "dependencies": { - "System.Text.Json": "8.0.3" - }, - "runtime": { - "Cyaim.WebSocketServer.dll": {} - } - }, - "System.Text.Encodings.Web/8.0.0": { - "runtime": { - "lib/net7.0/System.Text.Encodings.Web.dll": { - "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.23.53103" - } - }, - "runtimeTargets": { - "runtimes/browser/lib/net7.0/System.Text.Encodings.Web.dll": { - "rid": "browser", - "assetType": "runtime", - "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.23.53103" - } - } - }, - "System.Text.Json/8.0.3": { - "dependencies": { - "System.Text.Encodings.Web": "8.0.0" - }, - "runtime": { - "lib/net7.0/System.Text.Json.dll": { - "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.324.11423" - } - } - } - } - }, - "libraries": { - "Cyaim.WebSocketServer/1.6.3": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "System.Text.Encodings.Web/8.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", - "path": "system.text.encodings.web/8.0.0", - "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" - }, - "System.Text.Json/8.0.3": { - "type": "package", - "serviceable": true, - "sha512": "sha512-hpagS9joOwv6efWfrMmV9MjQXpiXZH72PgN067Ysfr6AWMSD1/1hEcvh/U5mUpPLezEWsOJSuVrmqDIVD958iA==", - "path": "system.text.json/8.0.3", - "hashPath": "system.text.json.8.0.3.nupkg.sha512" - } - } -} \ No newline at end of file diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net8.0/Cyaim.WebSocketServer.deps.json b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net8.0/Cyaim.WebSocketServer.deps.json deleted file mode 100644 index a6d7649..0000000 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/bin/Debug/net8.0/Cyaim.WebSocketServer.deps.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "runtimeTarget": { - "name": ".NETCoreApp,Version=v8.0", - "signature": "" - }, - "compilationOptions": {}, - "targets": { - ".NETCoreApp,Version=v8.0": { - "Cyaim.WebSocketServer/1.6.3": { - "dependencies": { - "System.Text.Json": "8.0.3" - }, - "runtime": { - "Cyaim.WebSocketServer.dll": {} - } - }, - "System.Text.Encodings.Web/8.0.0": {}, - "System.Text.Json/8.0.3": { - "dependencies": { - "System.Text.Encodings.Web": "8.0.0" - } - } - } - }, - "libraries": { - "Cyaim.WebSocketServer/1.6.3": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "System.Text.Encodings.Web/8.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", - "path": "system.text.encodings.web/8.0.0", - "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" - }, - "System.Text.Json/8.0.3": { - "type": "package", - "serviceable": true, - "sha512": "sha512-hpagS9joOwv6efWfrMmV9MjQXpiXZH72PgN067Ysfr6AWMSD1/1hEcvh/U5mUpPLezEWsOJSuVrmqDIVD958iA==", - "path": "system.text.json/8.0.3", - "hashPath": "system.text.json.8.0.3.nupkg.sha512" - } - } -} \ No newline at end of file From a51545f2e9cf4e0759c969e4ffdf09674a789b29 Mon Sep 17 00:00:00 2001 From: Joes Date: Mon, 20 May 2024 10:30:14 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=B0=8F=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Cyaim.WebSocketServer/Cyaim.WebSocketServer.csproj | 4 ---- .../Infrastructure/Configures/WebSocketRouteOption.cs | 4 ++-- .../Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs | 3 ++- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Cyaim.WebSocketServer.csproj b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Cyaim.WebSocketServer.csproj index 7e62899..0c5365c 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Cyaim.WebSocketServer.csproj +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Cyaim.WebSocketServer.csproj @@ -38,10 +38,6 @@ - - - - diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs index 9fc7d89..5f30d78 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs @@ -12,7 +12,7 @@ namespace Cyaim.WebSocketServer.Infrastructure.Configures /// /// WebSocketRoute run parameter /// - public sealed class WebSocketRouteOption + public class WebSocketRouteOption { /// /// Dependency injection container provider,Set on UseWebSocketServer @@ -107,7 +107,7 @@ public sealed class WebSocketRouteOption /// /// /// - public Task OnBeforeConnection(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) + public virtual Task OnBeforeConnection(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) { if (BeforeConnectionEvent != null) { diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs index 4b1d4f1..0742898 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs @@ -168,7 +168,8 @@ private async Task MvcForward(HttpContext context, WebSocket webSocket) } //await wsReceiveReader.WriteAsync(buffer, 0, result.Count); - await wsReceiveReader.WriteAsync(buffer.AsMemory(0, result.Count), connCts.Token); + // ReSharper disable once MethodSupportsCancellation + await wsReceiveReader.WriteAsync(buffer.AsMemory(0, result.Count)); // 已经接受完数据了 if (result.EndOfMessage || result.CloseStatus.HasValue) { From 0b4ec8f49f40bd41759b1e4f13099a0b8714d587 Mon Sep 17 00:00:00 2001 From: Joes Date: Mon, 20 May 2024 10:32:22 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=B0=8F=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Infrastructure/Configures/WebSocketRouteOption.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs index 5f30d78..7dfd480 100644 --- a/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs +++ b/Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Configures/WebSocketRouteOption.cs @@ -7,6 +7,8 @@ using System.Text.Json; using System.Threading.Tasks; +// ReSharper disable ClassWithVirtualMembersNeverInherited.Global + namespace Cyaim.WebSocketServer.Infrastructure.Configures { /// @@ -139,7 +141,7 @@ public virtual Task OnBeforeConnection(HttpContext context, WebSocketRoute /// /// /// - public Task OnDisConnected(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) + public virtual Task OnDisConnected(HttpContext context, WebSocketRouteOption webSocketOptions, string channel, ILogger logger) { if (DisConnectedEvent != null) {