From e8f3acc38f8ed70b27550234a97f6ca1a1114f26 Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Tue, 7 Jan 2025 15:08:42 +0900 Subject: [PATCH 1/3] Align LangVersion of all projects --- src/Directory.Build.props | 1 - src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj | 1 - src/MagicOnion.Client/MagicOnion.Client.csproj | 1 - src/MagicOnion.Internal/MagicOnion.Internal.csproj | 1 - src/MagicOnion.Server/MagicOnion.Server.csproj | 1 - src/MagicOnion.Shared/MagicOnion.Shared.csproj | 1 - 6 files changed, 6 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 1c254dc90..6030d05ea 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,7 +4,6 @@ latest - <_LangVersionUnityBaseline>9.0 diff --git a/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj b/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj index bc66af320..f9c9896fc 100644 --- a/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj +++ b/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj @@ -3,7 +3,6 @@ netstandard2.0;net8.0 - $(_LangVersionUnityBaseline) enable true diff --git a/src/MagicOnion.Client/MagicOnion.Client.csproj b/src/MagicOnion.Client/MagicOnion.Client.csproj index d07411374..ec4e31f1a 100644 --- a/src/MagicOnion.Client/MagicOnion.Client.csproj +++ b/src/MagicOnion.Client/MagicOnion.Client.csproj @@ -3,7 +3,6 @@ netstandard2.0;netstandard2.1;net8.0;net9.0 - $(_LangVersionUnityBaseline) enable true diff --git a/src/MagicOnion.Internal/MagicOnion.Internal.csproj b/src/MagicOnion.Internal/MagicOnion.Internal.csproj index 41656f73d..d225a2ac4 100644 --- a/src/MagicOnion.Internal/MagicOnion.Internal.csproj +++ b/src/MagicOnion.Internal/MagicOnion.Internal.csproj @@ -3,7 +3,6 @@ netstandard2.0;netstandard2.1;net8.0 - $(_LangVersionUnityBaseline) enable MagicOnion diff --git a/src/MagicOnion.Server/MagicOnion.Server.csproj b/src/MagicOnion.Server/MagicOnion.Server.csproj index 0dd3f04f8..9cc08af47 100644 --- a/src/MagicOnion.Server/MagicOnion.Server.csproj +++ b/src/MagicOnion.Server/MagicOnion.Server.csproj @@ -5,7 +5,6 @@ enable enable - latest $(DefineConstants);USE_OBJECTPOOL_STREAMINGHUBPAYLOADPOOL diff --git a/src/MagicOnion.Shared/MagicOnion.Shared.csproj b/src/MagicOnion.Shared/MagicOnion.Shared.csproj index c36483642..e163b4696 100644 --- a/src/MagicOnion.Shared/MagicOnion.Shared.csproj +++ b/src/MagicOnion.Shared/MagicOnion.Shared.csproj @@ -3,7 +3,6 @@ netstandard2.0;netstandard2.1;net8.0 - $(_LangVersionUnityBaseline) enable MagicOnion From 87fca7d19331f7526bcbdb448b3ee63e48bc0ef3 Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Tue, 7 Jan 2025 15:18:13 +0900 Subject: [PATCH 2/3] Enable ImplicitUsings --- .../Client/IResponseContext.cs | 7 +------ src/MagicOnion.Abstractions/ClientStreamingResult.cs | 6 ------ .../AsyncUnaryResultMethodBuilder.cs | 2 -- src/MagicOnion.Abstractions/DuplexStreamingResult.cs | 5 +---- src/MagicOnion.Abstractions/DynamicArgumentTuple.cs | 10 ---------- .../GenerateDefineDebugAttribute.cs | 6 ------ .../GenerateIfDirectiveAttribute.cs | 2 -- src/MagicOnion.Abstractions/IService.cs | 4 +--- src/MagicOnion.Abstractions/IStreamingHub.cs | 2 -- src/MagicOnion.Abstractions/IgnoreAttribute.cs | 6 ------ src/MagicOnion.Abstractions/Internal/Box.cs | 5 ----- .../Internal/IAsyncGrpcCallWrapper.cs | 4 ---- src/MagicOnion.Abstractions/Internal/RawBytesBox.cs | 1 - src/MagicOnion.Abstractions/InternalsVisibleTo.cs | 12 +++++------- .../MagicOnion.Abstractions.csproj | 1 + .../Server/Hubs/MethodIdAttribute.cs | 4 ---- src/MagicOnion.Abstractions/ServerStreamingResult.cs | 6 +----- src/MagicOnion.Abstractions/UnaryResult.cs | 2 -- src/MagicOnion.Client/ClientFilter.cs | 4 ---- src/MagicOnion.Client/ClientHeartbeatEvent.cs | 2 -- .../DynamicClient/DynamicClientBuilder.cs | 3 --- .../DynamicMagicOnionClientFactoryProvider.cs | 1 - .../DynamicStreamingHubClientBuilder.cs | 6 ------ .../DynamicStreamingHubClientFactoryProvider.cs | 1 - .../DynamicClient/RawMethodInvokerTypes.cs | 1 - .../DynamicClient/ServiceClientDefinition.cs | 4 ---- src/MagicOnion.Client/IMagicOnionAwareGrpcChannel.cs | 4 ---- src/MagicOnion.Client/IMagicOnionClientLogger.cs | 4 ---- src/MagicOnion.Client/IStreamingHubClient.cs | 3 --- .../IStreamingHubDiagnosticHandler.cs | 3 --- .../Internal/InterceptInvokeHelper.cs | 4 +--- .../Internal/MagicOnionMethodInvoker.cs | 5 ----- .../Internal/StreamingHubClientHeartbeatManager.cs | 6 ------ .../Internal/StreamingHubResponseTaskSource.cs | 2 -- src/MagicOnion.Client/MagicOnion.Client.csproj | 1 + src/MagicOnion.Client/MagicOnionClient.cs | 1 - src/MagicOnion.Client/MagicOnionClientBase.cs | 4 ---- .../MagicOnionClientFactoryProvider.cs | 2 -- .../MagicOnionClientGenerationAttribute.cs | 4 ---- src/MagicOnion.Client/RequestContext.cs | 2 -- src/MagicOnion.Client/ResponseContext.cs | 2 -- src/MagicOnion.Client/ServerHeartbeatEvent.cs | 2 -- src/MagicOnion.Client/StreamingHubClient.cs | 3 --- src/MagicOnion.Client/StreamingHubClientBase.cs | 6 ------ .../StreamingHubClientExtensions.cs | 3 --- .../StreamingHubClientFactoryProvider.cs | 2 -- src/MagicOnion.Internal/BroadcasterHelper.cs | 3 --- .../Buffers/ArrayPoolBufferWriter.cs | 1 - src/MagicOnion.Internal/GrpcMethodHelper.cs | 2 -- src/MagicOnion.Internal/MagicOnion.Internal.csproj | 1 + .../MagicOnionAsyncStreamReader.cs | 3 --- .../MagicOnionClientStreamWriter.cs | 2 -- src/MagicOnion.Internal/MagicOnionMarshallers.cs | 3 --- .../MagicOnionServerStreamWriter.cs | 2 -- .../Reflection/DynamicAssembly.cs | 1 - .../Reflection/ILGeneratorExtensions.cs | 2 -- .../StreamingHubClientMessageReader.cs | 1 - src/MagicOnion.Internal/StreamingHubMessageWriter.cs | 1 - src/MagicOnion.Internal/StreamingHubPayload.cs | 4 ---- .../StreamingHubPayloadPool.BuiltIn.cs | 3 --- .../StreamingHubServerMessageReader.cs | 1 - .../DynamicArgumentTupleFormatter.cs | 2 -- .../DynamicArgumentTupleFormatter.tt | 2 -- .../MessagePackMagicOnionSerializerProvider.cs | 2 -- .../UnsafeDirectBlitResolver.cs | 2 -- src/MagicOnion.Shared/MagicOnion.Shared.csproj | 1 + src/MagicOnion.Shared/MetadataExtensions.cs | 1 - 67 files changed, 14 insertions(+), 196 deletions(-) diff --git a/src/MagicOnion.Abstractions/Client/IResponseContext.cs b/src/MagicOnion.Abstractions/Client/IResponseContext.cs index f839eda7b..f9f3917d1 100644 --- a/src/MagicOnion.Abstractions/Client/IResponseContext.cs +++ b/src/MagicOnion.Abstractions/Client/IResponseContext.cs @@ -1,9 +1,4 @@ -using Grpc.Core; -using MessagePack; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; +using Grpc.Core; namespace MagicOnion.Client { diff --git a/src/MagicOnion.Abstractions/ClientStreamingResult.cs b/src/MagicOnion.Abstractions/ClientStreamingResult.cs index c46561a72..73031f0eb 100644 --- a/src/MagicOnion.Abstractions/ClientStreamingResult.cs +++ b/src/MagicOnion.Abstractions/ClientStreamingResult.cs @@ -1,11 +1,5 @@ using Grpc.Core; -using MessagePack; -using System; -using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; using MagicOnion.Internal; namespace MagicOnion diff --git a/src/MagicOnion.Abstractions/CompilerServices/AsyncUnaryResultMethodBuilder.cs b/src/MagicOnion.Abstractions/CompilerServices/AsyncUnaryResultMethodBuilder.cs index d26fde78b..514135f3e 100644 --- a/src/MagicOnion.Abstractions/CompilerServices/AsyncUnaryResultMethodBuilder.cs +++ b/src/MagicOnion.Abstractions/CompilerServices/AsyncUnaryResultMethodBuilder.cs @@ -1,7 +1,5 @@ -using System; using System.Runtime.CompilerServices; using System.Security; -using System.Threading.Tasks; using MessagePack; namespace MagicOnion.CompilerServices diff --git a/src/MagicOnion.Abstractions/DuplexStreamingResult.cs b/src/MagicOnion.Abstractions/DuplexStreamingResult.cs index 7d3956035..61537d3d5 100644 --- a/src/MagicOnion.Abstractions/DuplexStreamingResult.cs +++ b/src/MagicOnion.Abstractions/DuplexStreamingResult.cs @@ -1,7 +1,4 @@ using Grpc.Core; -using MessagePack; -using System; -using System.Threading.Tasks; using MagicOnion.Internal; namespace MagicOnion @@ -65,4 +62,4 @@ public void Dispose() inner?.Dispose(); } } -} \ No newline at end of file +} diff --git a/src/MagicOnion.Abstractions/DynamicArgumentTuple.cs b/src/MagicOnion.Abstractions/DynamicArgumentTuple.cs index 0e9e29912..3cdd3a4c2 100644 --- a/src/MagicOnion.Abstractions/DynamicArgumentTuple.cs +++ b/src/MagicOnion.Abstractions/DynamicArgumentTuple.cs @@ -1,15 +1,5 @@ - - - - - - - - -using System; using System.Runtime.InteropServices; using MessagePack; -using MessagePack.Formatters; namespace MagicOnion { diff --git a/src/MagicOnion.Abstractions/GenerateDefineDebugAttribute.cs b/src/MagicOnion.Abstractions/GenerateDefineDebugAttribute.cs index 1965ea622..57af85f59 100644 --- a/src/MagicOnion.Abstractions/GenerateDefineDebugAttribute.cs +++ b/src/MagicOnion.Abstractions/GenerateDefineDebugAttribute.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace MagicOnion { /// diff --git a/src/MagicOnion.Abstractions/GenerateIfDirectiveAttribute.cs b/src/MagicOnion.Abstractions/GenerateIfDirectiveAttribute.cs index fd50cd6fa..6ff3b157a 100644 --- a/src/MagicOnion.Abstractions/GenerateIfDirectiveAttribute.cs +++ b/src/MagicOnion.Abstractions/GenerateIfDirectiveAttribute.cs @@ -1,5 +1,3 @@ -using System; - namespace MagicOnion { /// diff --git a/src/MagicOnion.Abstractions/IService.cs b/src/MagicOnion.Abstractions/IService.cs index a2e5a3bfb..02c4e000e 100644 --- a/src/MagicOnion.Abstractions/IService.cs +++ b/src/MagicOnion.Abstractions/IService.cs @@ -1,6 +1,4 @@ -using Grpc.Core; -using System; -using System.Threading; +using Grpc.Core; namespace MagicOnion { diff --git a/src/MagicOnion.Abstractions/IStreamingHub.cs b/src/MagicOnion.Abstractions/IStreamingHub.cs index abca4c5d9..8b9178642 100644 --- a/src/MagicOnion.Abstractions/IStreamingHub.cs +++ b/src/MagicOnion.Abstractions/IStreamingHub.cs @@ -1,5 +1,3 @@ -using System.Threading.Tasks; - namespace MagicOnion { public interface IStreamingHubMarker diff --git a/src/MagicOnion.Abstractions/IgnoreAttribute.cs b/src/MagicOnion.Abstractions/IgnoreAttribute.cs index c92f80ab3..db16050d1 100644 --- a/src/MagicOnion.Abstractions/IgnoreAttribute.cs +++ b/src/MagicOnion.Abstractions/IgnoreAttribute.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace MagicOnion { /// diff --git a/src/MagicOnion.Abstractions/Internal/Box.cs b/src/MagicOnion.Abstractions/Internal/Box.cs index 63b6db870..d48e43998 100644 --- a/src/MagicOnion.Abstractions/Internal/Box.cs +++ b/src/MagicOnion.Abstractions/Internal/Box.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Runtime.CompilerServices; -using System.Text; -using MessagePack; namespace MagicOnion.Internal { diff --git a/src/MagicOnion.Abstractions/Internal/IAsyncGrpcCallWrapper.cs b/src/MagicOnion.Abstractions/Internal/IAsyncGrpcCallWrapper.cs index d43729614..6230555db 100644 --- a/src/MagicOnion.Abstractions/Internal/IAsyncGrpcCallWrapper.cs +++ b/src/MagicOnion.Abstractions/Internal/IAsyncGrpcCallWrapper.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; using Grpc.Core; namespace MagicOnion.Internal diff --git a/src/MagicOnion.Abstractions/Internal/RawBytesBox.cs b/src/MagicOnion.Abstractions/Internal/RawBytesBox.cs index 00b4a2e5f..1abb3365d 100644 --- a/src/MagicOnion.Abstractions/Internal/RawBytesBox.cs +++ b/src/MagicOnion.Abstractions/Internal/RawBytesBox.cs @@ -1,4 +1,3 @@ -using System; using System.ComponentModel; namespace MagicOnion.Internal diff --git a/src/MagicOnion.Abstractions/InternalsVisibleTo.cs b/src/MagicOnion.Abstractions/InternalsVisibleTo.cs index fcac9d922..a483baf92 100644 --- a/src/MagicOnion.Abstractions/InternalsVisibleTo.cs +++ b/src/MagicOnion.Abstractions/InternalsVisibleTo.cs @@ -1,13 +1,11 @@ -using System.Reflection; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; [assembly: InternalsVisibleTo("MagicOnion, PublicKey=" + - "0024000004800000940000000602000000240000525341310004000001000100f1ee449290a813" + - "77cf1a6d598f10a3e2de6c45ee5377140b179b7a2260007c4ba633a6f766a0b3392ae2160819d6" + - "25d9d9d65a134b722fd4e637793479d6c8d72490f9992293ee53933205620245e55fcddb7ce639" + - "5d72c94365a432808fbcf1bf8ff2932a1263715f8bc73bb25b96366f118c58e24da5f2bee32223" + - "948d7bc5")] + "0024000004800000940000000602000000240000525341310004000001000100f1ee449290a813" + + "77cf1a6d598f10a3e2de6c45ee5377140b179b7a2260007c4ba633a6f766a0b3392ae2160819d6" + + "25d9d9d65a134b722fd4e637793479d6c8d72490f9992293ee53933205620245e55fcddb7ce639" + + "5d72c94365a432808fbcf1bf8ff2932a1263715f8bc73bb25b96366f118c58e24da5f2bee32223" + + "948d7bc5")] [assembly: InternalsVisibleTo("MagicOnion.Server, PublicKey=" + "0024000004800000940000000602000000240000525341310004000001000100f1ee449290a813" + diff --git a/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj b/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj index f9c9896fc..b15e29714 100644 --- a/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj +++ b/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj @@ -3,6 +3,7 @@ netstandard2.0;net8.0 + enable enable true diff --git a/src/MagicOnion.Abstractions/Server/Hubs/MethodIdAttribute.cs b/src/MagicOnion.Abstractions/Server/Hubs/MethodIdAttribute.cs index 0eb685db5..202ca1b63 100644 --- a/src/MagicOnion.Abstractions/Server/Hubs/MethodIdAttribute.cs +++ b/src/MagicOnion.Abstractions/Server/Hubs/MethodIdAttribute.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace MagicOnion.Server.Hubs { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] diff --git a/src/MagicOnion.Abstractions/ServerStreamingResult.cs b/src/MagicOnion.Abstractions/ServerStreamingResult.cs index 9180c210d..cc0c28649 100644 --- a/src/MagicOnion.Abstractions/ServerStreamingResult.cs +++ b/src/MagicOnion.Abstractions/ServerStreamingResult.cs @@ -1,8 +1,4 @@ using Grpc.Core; -using MessagePack; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; using MagicOnion.Internal; namespace MagicOnion @@ -58,4 +54,4 @@ public Metadata GetTrailers() public void Dispose() => inner?.Dispose(); } -} \ No newline at end of file +} diff --git a/src/MagicOnion.Abstractions/UnaryResult.cs b/src/MagicOnion.Abstractions/UnaryResult.cs index b73727cd4..c3367c177 100644 --- a/src/MagicOnion.Abstractions/UnaryResult.cs +++ b/src/MagicOnion.Abstractions/UnaryResult.cs @@ -1,9 +1,7 @@ using Grpc.Core; using MagicOnion.Client; using MagicOnion.CompilerServices; // require this using in AsyncMethodBuilder -using System; using System.Runtime.CompilerServices; -using System.Threading.Tasks; using MessagePack; namespace MagicOnion diff --git a/src/MagicOnion.Client/ClientFilter.cs b/src/MagicOnion.Client/ClientFilter.cs index 27ad9ecf0..f6305b7a0 100644 --- a/src/MagicOnion.Client/ClientFilter.cs +++ b/src/MagicOnion.Client/ClientFilter.cs @@ -1,7 +1,3 @@ -using System; -using System.Text; -using System.Threading.Tasks; - namespace MagicOnion.Client { public interface IClientFilter diff --git a/src/MagicOnion.Client/ClientHeartbeatEvent.cs b/src/MagicOnion.Client/ClientHeartbeatEvent.cs index 690c2df48..4110ae615 100644 --- a/src/MagicOnion.Client/ClientHeartbeatEvent.cs +++ b/src/MagicOnion.Client/ClientHeartbeatEvent.cs @@ -1,5 +1,3 @@ -using System; - namespace MagicOnion.Client { /// diff --git a/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs b/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs index 7be683746..60b433997 100644 --- a/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs +++ b/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Reflection; using System.Reflection.Emit; using Grpc.Core; diff --git a/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs b/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs index 47a7d3d42..0b3b64d81 100644 --- a/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs +++ b/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics.CodeAnalysis; namespace MagicOnion.Client.DynamicClient diff --git a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs index 9173e8f06..7646f8562 100644 --- a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs +++ b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs @@ -1,17 +1,11 @@ using Grpc.Core; using MagicOnion.Internal; using MagicOnion.Internal.Reflection; -using MagicOnion.Serialization; using MagicOnion.Server.Hubs; using MessagePack; -using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Reflection; using System.Reflection.Emit; -using System.Threading; -using System.Threading.Tasks; namespace MagicOnion.Client.DynamicClient { diff --git a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs index d6ee35879..4e2b59443 100644 --- a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs +++ b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics.CodeAnalysis; namespace MagicOnion.Client.DynamicClient diff --git a/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs b/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs index 80a85c9b3..a0bc47ce6 100644 --- a/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs +++ b/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; using MagicOnion.Client.Internal; diff --git a/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs b/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs index 8e4519d22..44c54d0da 100644 --- a/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs +++ b/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Reflection; -using System.Threading.Tasks; using Grpc.Core; using MessagePack; diff --git a/src/MagicOnion.Client/IMagicOnionAwareGrpcChannel.cs b/src/MagicOnion.Client/IMagicOnionAwareGrpcChannel.cs index 0b4359895..01cfb3171 100644 --- a/src/MagicOnion.Client/IMagicOnionAwareGrpcChannel.cs +++ b/src/MagicOnion.Client/IMagicOnionAwareGrpcChannel.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; using Grpc.Core; namespace MagicOnion.Client diff --git a/src/MagicOnion.Client/IMagicOnionClientLogger.cs b/src/MagicOnion.Client/IMagicOnionClientLogger.cs index 4e6801650..51752bda0 100644 --- a/src/MagicOnion.Client/IMagicOnionClientLogger.cs +++ b/src/MagicOnion.Client/IMagicOnionClientLogger.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace MagicOnion.Client { public interface IMagicOnionClientLogger diff --git a/src/MagicOnion.Client/IStreamingHubClient.cs b/src/MagicOnion.Client/IStreamingHubClient.cs index 2f9068a96..b49402e85 100644 --- a/src/MagicOnion.Client/IStreamingHubClient.cs +++ b/src/MagicOnion.Client/IStreamingHubClient.cs @@ -1,6 +1,3 @@ -using System; -using System.Threading.Tasks; - namespace MagicOnion.Client { /// diff --git a/src/MagicOnion.Client/IStreamingHubDiagnosticHandler.cs b/src/MagicOnion.Client/IStreamingHubDiagnosticHandler.cs index 83f6a513f..91b0ad26b 100644 --- a/src/MagicOnion.Client/IStreamingHubDiagnosticHandler.cs +++ b/src/MagicOnion.Client/IStreamingHubDiagnosticHandler.cs @@ -1,6 +1,3 @@ -using System; -using System.Threading.Tasks; - namespace MagicOnion.Client { /// diff --git a/src/MagicOnion.Client/Internal/InterceptInvokeHelper.cs b/src/MagicOnion.Client/Internal/InterceptInvokeHelper.cs index 8ba2fba55..24a98454d 100644 --- a/src/MagicOnion.Client/Internal/InterceptInvokeHelper.cs +++ b/src/MagicOnion.Client/Internal/InterceptInvokeHelper.cs @@ -1,5 +1,3 @@ -using System.Threading.Tasks; - namespace MagicOnion.Client.Internal { internal static class InterceptInvokeHelper @@ -155,4 +153,4 @@ static ValueTask InvokeRecursive(int index, RequestContext cont } } } -} \ No newline at end of file +} diff --git a/src/MagicOnion.Client/Internal/MagicOnionMethodInvoker.cs b/src/MagicOnion.Client/Internal/MagicOnionMethodInvoker.cs index 4c7714da7..8ef8d1c84 100644 --- a/src/MagicOnion.Client/Internal/MagicOnionMethodInvoker.cs +++ b/src/MagicOnion.Client/Internal/MagicOnionMethodInvoker.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; using Grpc.Core; using MagicOnion.Internal; using MagicOnion.Serialization; diff --git a/src/MagicOnion.Client/Internal/StreamingHubClientHeartbeatManager.cs b/src/MagicOnion.Client/Internal/StreamingHubClientHeartbeatManager.cs index fb4778171..176beccbf 100644 --- a/src/MagicOnion.Client/Internal/StreamingHubClientHeartbeatManager.cs +++ b/src/MagicOnion.Client/Internal/StreamingHubClientHeartbeatManager.cs @@ -1,11 +1,5 @@ -using System; -using System.Diagnostics; -using System.Threading; using System.Threading.Channels; -using System.Threading.Tasks; using MagicOnion.Internal; -using MagicOnion.Internal.Buffers; -using MessagePack; namespace MagicOnion.Client.Internal { diff --git a/src/MagicOnion.Client/Internal/StreamingHubResponseTaskSource.cs b/src/MagicOnion.Client/Internal/StreamingHubResponseTaskSource.cs index 99908b14a..2c12af2b9 100644 --- a/src/MagicOnion.Client/Internal/StreamingHubResponseTaskSource.cs +++ b/src/MagicOnion.Client/Internal/StreamingHubResponseTaskSource.cs @@ -1,7 +1,5 @@ using MagicOnion.Internal; -using System; using System.Diagnostics; -using System.Threading.Tasks; using System.Threading.Tasks.Sources; namespace MagicOnion.Client.Internal diff --git a/src/MagicOnion.Client/MagicOnion.Client.csproj b/src/MagicOnion.Client/MagicOnion.Client.csproj index ec4e31f1a..f8c69d051 100644 --- a/src/MagicOnion.Client/MagicOnion.Client.csproj +++ b/src/MagicOnion.Client/MagicOnion.Client.csproj @@ -3,6 +3,7 @@ netstandard2.0;netstandard2.1;net8.0;net9.0 + enable enable true diff --git a/src/MagicOnion.Client/MagicOnionClient.cs b/src/MagicOnion.Client/MagicOnionClient.cs index f43ac754f..f0a524dd1 100644 --- a/src/MagicOnion.Client/MagicOnionClient.cs +++ b/src/MagicOnion.Client/MagicOnionClient.cs @@ -1,6 +1,5 @@ using Grpc.Core; using MagicOnion.Serialization; -using System; namespace MagicOnion.Client { diff --git a/src/MagicOnion.Client/MagicOnionClientBase.cs b/src/MagicOnion.Client/MagicOnionClientBase.cs index 035841aca..1756171e6 100644 --- a/src/MagicOnion.Client/MagicOnionClientBase.cs +++ b/src/MagicOnion.Client/MagicOnionClientBase.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; using Grpc.Core; namespace MagicOnion.Client diff --git a/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs b/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs index 10f1365b1..88331d7e8 100644 --- a/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs +++ b/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs @@ -1,7 +1,5 @@ using MagicOnion.Serialization; -using System; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Runtime.CompilerServices; namespace MagicOnion.Client diff --git a/src/MagicOnion.Client/MagicOnionClientGenerationAttribute.cs b/src/MagicOnion.Client/MagicOnionClientGenerationAttribute.cs index d8e75a225..8c36c93e3 100644 --- a/src/MagicOnion.Client/MagicOnionClientGenerationAttribute.cs +++ b/src/MagicOnion.Client/MagicOnionClientGenerationAttribute.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace MagicOnion.Client { /// diff --git a/src/MagicOnion.Client/RequestContext.cs b/src/MagicOnion.Client/RequestContext.cs index bd91649cb..a10905506 100644 --- a/src/MagicOnion.Client/RequestContext.cs +++ b/src/MagicOnion.Client/RequestContext.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using Grpc.Core; namespace MagicOnion.Client diff --git a/src/MagicOnion.Client/ResponseContext.cs b/src/MagicOnion.Client/ResponseContext.cs index b9f1bbf8b..fe640c972 100644 --- a/src/MagicOnion.Client/ResponseContext.cs +++ b/src/MagicOnion.Client/ResponseContext.cs @@ -1,5 +1,3 @@ -using System; -using System.Threading.Tasks; using Grpc.Core; using MagicOnion.Internal; diff --git a/src/MagicOnion.Client/ServerHeartbeatEvent.cs b/src/MagicOnion.Client/ServerHeartbeatEvent.cs index d19441608..03ddee42e 100644 --- a/src/MagicOnion.Client/ServerHeartbeatEvent.cs +++ b/src/MagicOnion.Client/ServerHeartbeatEvent.cs @@ -1,5 +1,3 @@ -using System; - namespace MagicOnion.Client { /// diff --git a/src/MagicOnion.Client/StreamingHubClient.cs b/src/MagicOnion.Client/StreamingHubClient.cs index 833b91939..0f6c51b56 100644 --- a/src/MagicOnion.Client/StreamingHubClient.cs +++ b/src/MagicOnion.Client/StreamingHubClient.cs @@ -1,8 +1,5 @@ using Grpc.Core; using MagicOnion.Serialization; -using System; -using System.Threading; -using System.Threading.Tasks; namespace MagicOnion.Client { diff --git a/src/MagicOnion.Client/StreamingHubClientBase.cs b/src/MagicOnion.Client/StreamingHubClientBase.cs index 7199597a7..1a0f95ccc 100644 --- a/src/MagicOnion.Client/StreamingHubClientBase.cs +++ b/src/MagicOnion.Client/StreamingHubClientBase.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; using System.Buffers; -using System.Diagnostics; -using System.Linq; using System.Threading.Channels; using Grpc.Core; using MagicOnion.Internal; diff --git a/src/MagicOnion.Client/StreamingHubClientExtensions.cs b/src/MagicOnion.Client/StreamingHubClientExtensions.cs index fc90df02e..9a74070d3 100644 --- a/src/MagicOnion.Client/StreamingHubClientExtensions.cs +++ b/src/MagicOnion.Client/StreamingHubClientExtensions.cs @@ -1,6 +1,3 @@ -using System; -using System.Threading.Tasks; - namespace MagicOnion.Client { public static class StreamingHubClientExtensions diff --git a/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs b/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs index 63ef1ba01..bf71e8cc5 100644 --- a/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs +++ b/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs @@ -1,7 +1,5 @@ using Grpc.Core; -using System; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Runtime.CompilerServices; namespace MagicOnion.Client diff --git a/src/MagicOnion.Internal/BroadcasterHelper.cs b/src/MagicOnion.Internal/BroadcasterHelper.cs index f87114cb5..57c294379 100644 --- a/src/MagicOnion.Internal/BroadcasterHelper.cs +++ b/src/MagicOnion.Internal/BroadcasterHelper.cs @@ -1,8 +1,5 @@ using MagicOnion.Server.Hubs; -using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Reflection; namespace MagicOnion.Internal diff --git a/src/MagicOnion.Internal/Buffers/ArrayPoolBufferWriter.cs b/src/MagicOnion.Internal/Buffers/ArrayPoolBufferWriter.cs index 8c5806321..6474f0350 100644 --- a/src/MagicOnion.Internal/Buffers/ArrayPoolBufferWriter.cs +++ b/src/MagicOnion.Internal/Buffers/ArrayPoolBufferWriter.cs @@ -1,4 +1,3 @@ -using System; using System.Buffers; using System.Diagnostics; diff --git a/src/MagicOnion.Internal/GrpcMethodHelper.cs b/src/MagicOnion.Internal/GrpcMethodHelper.cs index 0d59cdc55..cb959516a 100644 --- a/src/MagicOnion.Internal/GrpcMethodHelper.cs +++ b/src/MagicOnion.Internal/GrpcMethodHelper.cs @@ -1,5 +1,3 @@ -using System; -using System.Reflection; using System.Runtime.CompilerServices; using Grpc.Core; using MagicOnion.Serialization; diff --git a/src/MagicOnion.Internal/MagicOnion.Internal.csproj b/src/MagicOnion.Internal/MagicOnion.Internal.csproj index d225a2ac4..80cf2c730 100644 --- a/src/MagicOnion.Internal/MagicOnion.Internal.csproj +++ b/src/MagicOnion.Internal/MagicOnion.Internal.csproj @@ -3,6 +3,7 @@ netstandard2.0;netstandard2.1;net8.0 + enable enable MagicOnion diff --git a/src/MagicOnion.Internal/MagicOnionAsyncStreamReader.cs b/src/MagicOnion.Internal/MagicOnionAsyncStreamReader.cs index 09b8e805b..ba8e4c038 100644 --- a/src/MagicOnion.Internal/MagicOnionAsyncStreamReader.cs +++ b/src/MagicOnion.Internal/MagicOnionAsyncStreamReader.cs @@ -1,6 +1,3 @@ -using System; -using System.Threading; -using System.Threading.Tasks; using Grpc.Core; namespace MagicOnion.Internal diff --git a/src/MagicOnion.Internal/MagicOnionClientStreamWriter.cs b/src/MagicOnion.Internal/MagicOnionClientStreamWriter.cs index 8993dbd71..b95d4f079 100644 --- a/src/MagicOnion.Internal/MagicOnionClientStreamWriter.cs +++ b/src/MagicOnion.Internal/MagicOnionClientStreamWriter.cs @@ -1,5 +1,3 @@ -using System; -using System.Threading.Tasks; using Grpc.Core; namespace MagicOnion.Internal diff --git a/src/MagicOnion.Internal/MagicOnionMarshallers.cs b/src/MagicOnion.Internal/MagicOnionMarshallers.cs index 33360672c..6cb349f7c 100644 --- a/src/MagicOnion.Internal/MagicOnionMarshallers.cs +++ b/src/MagicOnion.Internal/MagicOnionMarshallers.cs @@ -1,9 +1,6 @@ using Grpc.Core; using MessagePack; -using System; -using System.Buffers; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Reflection; namespace MagicOnion.Internal diff --git a/src/MagicOnion.Internal/MagicOnionServerStreamWriter.cs b/src/MagicOnion.Internal/MagicOnionServerStreamWriter.cs index 0ead3ca6d..6c6fd1c78 100644 --- a/src/MagicOnion.Internal/MagicOnionServerStreamWriter.cs +++ b/src/MagicOnion.Internal/MagicOnionServerStreamWriter.cs @@ -1,5 +1,3 @@ -using System; -using System.Threading.Tasks; using Grpc.Core; namespace MagicOnion.Internal diff --git a/src/MagicOnion.Internal/Reflection/DynamicAssembly.cs b/src/MagicOnion.Internal/Reflection/DynamicAssembly.cs index 6914ec17f..7cf8d8b5c 100644 --- a/src/MagicOnion.Internal/Reflection/DynamicAssembly.cs +++ b/src/MagicOnion.Internal/Reflection/DynamicAssembly.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Reflection.Emit; diff --git a/src/MagicOnion.Internal/Reflection/ILGeneratorExtensions.cs b/src/MagicOnion.Internal/Reflection/ILGeneratorExtensions.cs index 23d68e22c..effaca280 100644 --- a/src/MagicOnion.Internal/Reflection/ILGeneratorExtensions.cs +++ b/src/MagicOnion.Internal/Reflection/ILGeneratorExtensions.cs @@ -1,5 +1,3 @@ -using System; -using System.Reflection; using System.Reflection.Emit; namespace MagicOnion.Internal.Reflection diff --git a/src/MagicOnion.Internal/StreamingHubClientMessageReader.cs b/src/MagicOnion.Internal/StreamingHubClientMessageReader.cs index 7db110485..2cbb566d3 100644 --- a/src/MagicOnion.Internal/StreamingHubClientMessageReader.cs +++ b/src/MagicOnion.Internal/StreamingHubClientMessageReader.cs @@ -1,4 +1,3 @@ -using System; using MessagePack; namespace MagicOnion.Internal diff --git a/src/MagicOnion.Internal/StreamingHubMessageWriter.cs b/src/MagicOnion.Internal/StreamingHubMessageWriter.cs index feebe14f6..1bac680b0 100644 --- a/src/MagicOnion.Internal/StreamingHubMessageWriter.cs +++ b/src/MagicOnion.Internal/StreamingHubMessageWriter.cs @@ -1,4 +1,3 @@ -using System; using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; diff --git a/src/MagicOnion.Internal/StreamingHubPayload.cs b/src/MagicOnion.Internal/StreamingHubPayload.cs index 35582b9dc..e61398cca 100644 --- a/src/MagicOnion.Internal/StreamingHubPayload.cs +++ b/src/MagicOnion.Internal/StreamingHubPayload.cs @@ -1,9 +1,5 @@ -#nullable enable -using System; using System.Buffers; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Threading; namespace MagicOnion.Internal { diff --git a/src/MagicOnion.Internal/StreamingHubPayloadPool.BuiltIn.cs b/src/MagicOnion.Internal/StreamingHubPayloadPool.BuiltIn.cs index 2245d3e88..8030a54da 100644 --- a/src/MagicOnion.Internal/StreamingHubPayloadPool.BuiltIn.cs +++ b/src/MagicOnion.Internal/StreamingHubPayloadPool.BuiltIn.cs @@ -1,10 +1,7 @@ #if !USE_OBJECTPOOL_STREAMINGHUBPAYLOADPOOL -#nullable enable -using System; using System.Buffers; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -using System.Threading; namespace MagicOnion.Internal { diff --git a/src/MagicOnion.Internal/StreamingHubServerMessageReader.cs b/src/MagicOnion.Internal/StreamingHubServerMessageReader.cs index 1d00e3c38..dcedfcb63 100644 --- a/src/MagicOnion.Internal/StreamingHubServerMessageReader.cs +++ b/src/MagicOnion.Internal/StreamingHubServerMessageReader.cs @@ -1,4 +1,3 @@ -using System; using MessagePack; namespace MagicOnion.Internal diff --git a/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.cs b/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.cs index 5657b025f..f16dd70d0 100644 --- a/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.cs +++ b/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.cs @@ -1,6 +1,4 @@  -using System; -using System.Runtime.InteropServices; using MessagePack; using MessagePack.Formatters; diff --git a/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.tt b/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.tt index 2758a5f7f..54097a0ae 100644 --- a/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.tt +++ b/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.tt @@ -6,8 +6,6 @@ <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> -using System; -using System.Runtime.InteropServices; using MessagePack; using MessagePack.Formatters; diff --git a/src/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs b/src/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs index 298bb14cc..4386f6168 100644 --- a/src/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs +++ b/src/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs @@ -1,6 +1,4 @@ -using System; using System.Buffers; -using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using Grpc.Core; diff --git a/src/MagicOnion.Serialization.MessagePack/UnsafeDirectBlitResolver.cs b/src/MagicOnion.Serialization.MessagePack/UnsafeDirectBlitResolver.cs index 4dcefb943..6e97a580f 100644 --- a/src/MagicOnion.Serialization.MessagePack/UnsafeDirectBlitResolver.cs +++ b/src/MagicOnion.Serialization.MessagePack/UnsafeDirectBlitResolver.cs @@ -1,8 +1,6 @@ using MessagePack; using System.Buffers; using MessagePack.Formatters; -using System; -using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/MagicOnion.Shared/MagicOnion.Shared.csproj b/src/MagicOnion.Shared/MagicOnion.Shared.csproj index e163b4696..ad5820abe 100644 --- a/src/MagicOnion.Shared/MagicOnion.Shared.csproj +++ b/src/MagicOnion.Shared/MagicOnion.Shared.csproj @@ -3,6 +3,7 @@ netstandard2.0;netstandard2.1;net8.0 + enable enable MagicOnion diff --git a/src/MagicOnion.Shared/MetadataExtensions.cs b/src/MagicOnion.Shared/MetadataExtensions.cs index b56870da4..5815dbc10 100644 --- a/src/MagicOnion.Shared/MetadataExtensions.cs +++ b/src/MagicOnion.Shared/MetadataExtensions.cs @@ -1,5 +1,4 @@ using Grpc.Core; -using System; namespace MagicOnion { From 9ca5dc1f38b1824d41e860c6464dbdc648f0c958 Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Tue, 7 Jan 2025 15:25:33 +0900 Subject: [PATCH 3/3] To file-scoped namespace --- .../Client/IResponseContext.cs | 23 +- .../ClientStreamingResult.cs | 141 +- .../AsyncUnaryResultMethodBuilder.cs | 201 +- .../DuplexStreamingResult.cs | 103 +- .../DynamicArgumentTuple.cs | 947 +++--- .../GenerateDefineDebugAttribute.cs | 19 +- .../GenerateIfDirectiveAttribute.cs | 19 +- src/MagicOnion.Abstractions/IService.cs | 25 +- src/MagicOnion.Abstractions/IStreamingHub.cs | 19 +- .../IgnoreAttribute.cs | 15 +- src/MagicOnion.Abstractions/Internal/Box.cs | 85 +- .../Internal/IAsyncGrpcCallWrapper.cs | 41 +- .../Internal/RawBytesBox.cs | 19 +- .../Serialization/MagicOnionSerializer.cs | 39 +- .../Server/Hubs/MethodIdAttribute.cs | 17 +- .../ServerStreamingResult.cs | 99 +- src/MagicOnion.Abstractions/UnaryResult.cs | 525 ++-- src/MagicOnion.Client/ClientFilter.cs | 9 +- src/MagicOnion.Client/ClientHeartbeatEvent.cs | 23 +- .../DynamicClientAssemblyHolder.cs | 27 +- .../DynamicClient/DynamicClientBuilder.cs | 443 ++- .../DynamicMagicOnionClientFactoryProvider.cs | 57 +- .../DynamicStreamingHubClientBuilder.cs | 1227 ++++---- ...ynamicStreamingHubClientFactoryProvider.cs | 51 +- .../DynamicClient/RawMethodInvokerTypes.cs | 45 +- .../DynamicClient/ServiceClientDefinition.cs | 377 ++- .../IMagicOnionAwareGrpcChannel.cs | 53 +- .../IMagicOnionClientLogger.cs | 43 +- src/MagicOnion.Client/IStreamingHubClient.cs | 84 +- .../IStreamingHubDiagnosticHandler.cs | 91 +- .../Internal/InterceptInvokeHelper.cs | 271 +- .../Internal/MagicOnionMethodInvoker.cs | 281 +- .../StreamingHubClientHeartbeatManager.cs | 325 +- .../StreamingHubResponseTaskSource.cs | 135 +- src/MagicOnion.Client/MagicOnionClient.cs | 83 +- src/MagicOnion.Client/MagicOnionClientBase.cs | 97 +- .../MagicOnionClientFactoryProvider.cs | 89 +- .../MagicOnionClientGenerationAttribute.cs | 81 +- src/MagicOnion.Client/RequestContext.cs | 69 +- src/MagicOnion.Client/ResponseContext.cs | 181 +- src/MagicOnion.Client/ServerHeartbeatEvent.cs | 33 +- src/MagicOnion.Client/StreamingHubClient.cs | 133 +- .../StreamingHubClientBase.cs | 1149 ++++--- .../StreamingHubClientExtensions.cs | 41 +- .../StreamingHubClientFactoryProvider.cs | 92 +- src/MagicOnion.Internal/BroadcasterHelper.cs | 131 +- .../Buffers/ArrayPoolBufferWriter.cs | 145 +- src/MagicOnion.Internal/DangerousDummyNull.cs | 176 +- src/MagicOnion.Internal/FNV1A32.cs | 31 +- src/MagicOnion.Internal/GrpcMethodHelper.cs | 219 +- .../MagicOnionAsyncStreamReader.cs | 25 +- .../MagicOnionClientStreamWriter.cs | 33 +- .../MagicOnionMarshallers.cs | 108 +- .../MagicOnionServerStreamWriter.cs | 29 +- .../RequiresUnreferencedCodeAttribute.cs | 21 +- .../UnconditionalSuppressMessageAttribute.cs | 31 +- .../Reflection/ILGeneratorExtensions.cs | 277 +- .../StreamingHubClientMessageReader.cs | 189 +- .../StreamingHubMessageWriter.cs | 691 +++-- .../StreamingHubPayload.cs | 191 +- .../StreamingHubPayloadPool.BuiltIn.cs | 151 +- .../StreamingHubServerMessageReader.cs | 173 +- ...DynamicArgumentTupleMemoryPackFormatter.cs | 1111 ++++--- ...DynamicArgumentTupleMemoryPackFormatter.tt | 67 +- .../MemoryPackMagicOnionSerializer.cs | 60 +- .../PreserveAttribute.cs | 11 +- .../DynamicArgumentTupleFormatter.cs | 2651 ++++++++--------- .../DynamicArgumentTupleFormatter.tt | 77 +- src/MagicOnion.Shared/MetadataExtensions.cs | 75 +- .../Serialization/MagicOnionSerializer.cs | 17 +- 70 files changed, 7263 insertions(+), 7354 deletions(-) diff --git a/src/MagicOnion.Abstractions/Client/IResponseContext.cs b/src/MagicOnion.Abstractions/Client/IResponseContext.cs index f9f3917d1..6e27d1d2f 100644 --- a/src/MagicOnion.Abstractions/Client/IResponseContext.cs +++ b/src/MagicOnion.Abstractions/Client/IResponseContext.cs @@ -1,17 +1,16 @@ using Grpc.Core; -namespace MagicOnion.Client +namespace MagicOnion.Client; + +public interface IResponseContext : IDisposable { - public interface IResponseContext : IDisposable - { - Task ResponseHeadersAsync { get; } - Status GetStatus(); - Metadata GetTrailers(); - Type ResponseType { get; } - } + Task ResponseHeadersAsync { get; } + Status GetStatus(); + Metadata GetTrailers(); + Type ResponseType { get; } +} - public interface IResponseContext : IResponseContext - { - Task ResponseAsync { get; } - } +public interface IResponseContext : IResponseContext +{ + Task ResponseAsync { get; } } diff --git a/src/MagicOnion.Abstractions/ClientStreamingResult.cs b/src/MagicOnion.Abstractions/ClientStreamingResult.cs index 73031f0eb..b86852263 100644 --- a/src/MagicOnion.Abstractions/ClientStreamingResult.cs +++ b/src/MagicOnion.Abstractions/ClientStreamingResult.cs @@ -2,86 +2,85 @@ using System.Runtime.CompilerServices; using MagicOnion.Internal; -namespace MagicOnion +namespace MagicOnion; + +/// +/// Wrapped AsyncClientStreamingCall. +/// +public struct ClientStreamingResult : IDisposable { - /// - /// Wrapped AsyncClientStreamingCall. - /// - public struct ClientStreamingResult : IDisposable - { - internal readonly TResponse? rawValue; - internal readonly bool hasRawValue; - readonly IAsyncClientStreamingCallWrapper? inner; + internal readonly TResponse? rawValue; + internal readonly bool hasRawValue; + readonly IAsyncClientStreamingCallWrapper? inner; - public ClientStreamingResult(TResponse rawValue) - { - this.hasRawValue = true; - this.rawValue = rawValue; - this.inner = null; - } + public ClientStreamingResult(TResponse rawValue) + { + this.hasRawValue = true; + this.rawValue = rawValue; + this.inner = null; + } - public ClientStreamingResult(IAsyncClientStreamingCallWrapper inner) - { - this.hasRawValue = false; - this.rawValue = default(TResponse); - this.inner = inner; - } + public ClientStreamingResult(IAsyncClientStreamingCallWrapper inner) + { + this.hasRawValue = false; + this.rawValue = default(TResponse); + this.inner = inner; + } - IAsyncClientStreamingCallWrapper GetRequiredInner() - => inner ?? throw new NotSupportedException("ClientStreamingResult has no inner stream."); + IAsyncClientStreamingCallWrapper GetRequiredInner() + => inner ?? throw new NotSupportedException("ClientStreamingResult has no inner stream."); - /// - /// Asynchronous call result. - /// - public Task ResponseAsync - => hasRawValue ? Task.FromResult(rawValue!) : GetRequiredInner().ResponseAsync; + /// + /// Asynchronous call result. + /// + public Task ResponseAsync + => hasRawValue ? Task.FromResult(rawValue!) : GetRequiredInner().ResponseAsync; - /// - /// Asynchronous access to response headers. - /// - public Task ResponseHeadersAsync - => GetRequiredInner().ResponseHeadersAsync; + /// + /// Asynchronous access to response headers. + /// + public Task ResponseHeadersAsync + => GetRequiredInner().ResponseHeadersAsync; - /// - /// Async stream to send streaming requests. - /// - public IClientStreamWriter RequestStream - => GetRequiredInner().RequestStream; + /// + /// Async stream to send streaming requests. + /// + public IClientStreamWriter RequestStream + => GetRequiredInner().RequestStream; - /// - /// Allows awaiting this object directly. - /// - /// - public TaskAwaiter GetAwaiter() - { - return ResponseAsync.GetAwaiter(); - } + /// + /// Allows awaiting this object directly. + /// + /// + public TaskAwaiter GetAwaiter() + { + return ResponseAsync.GetAwaiter(); + } - /// - /// Gets the call status if the call has already finished. - /// Throws InvalidOperationException otherwise. - /// - public Status GetStatus() - => GetRequiredInner().GetStatus(); + /// + /// Gets the call status if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// + public Status GetStatus() + => GetRequiredInner().GetStatus(); - /// - /// Gets the call trailing metadata if the call has already finished. - /// Throws InvalidOperationException otherwise. - /// - public Metadata GetTrailers() - => GetRequiredInner().GetTrailers(); + /// + /// Gets the call trailing metadata if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// + public Metadata GetTrailers() + => GetRequiredInner().GetTrailers(); - /// - /// Provides means to cleanup after the call. - /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything. - /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. - /// As a result, all resources being used by the call should be released eventually. - /// - /// - /// Normally, there is no need for you to dispose the call unless you want to utilize the - /// "Cancel" semantics of invoking Dispose. - /// - public void Dispose() - => inner?.Dispose(); - } + /// + /// Provides means to cleanup after the call. + /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything. + /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. + /// As a result, all resources being used by the call should be released eventually. + /// + /// + /// Normally, there is no need for you to dispose the call unless you want to utilize the + /// "Cancel" semantics of invoking Dispose. + /// + public void Dispose() + => inner?.Dispose(); } diff --git a/src/MagicOnion.Abstractions/CompilerServices/AsyncUnaryResultMethodBuilder.cs b/src/MagicOnion.Abstractions/CompilerServices/AsyncUnaryResultMethodBuilder.cs index 514135f3e..c06aa39d1 100644 --- a/src/MagicOnion.Abstractions/CompilerServices/AsyncUnaryResultMethodBuilder.cs +++ b/src/MagicOnion.Abstractions/CompilerServices/AsyncUnaryResultMethodBuilder.cs @@ -2,141 +2,140 @@ using System.Security; using MessagePack; -namespace MagicOnion.CompilerServices +namespace MagicOnion.CompilerServices; + +public struct AsyncUnaryResultMethodBuilder { - public struct AsyncUnaryResultMethodBuilder - { - AsyncTaskMethodBuilder methodBuilder; - bool hasResult; - bool useBuilder; + AsyncTaskMethodBuilder methodBuilder; + bool hasResult; + bool useBuilder; - public static AsyncUnaryResultMethodBuilder Create() - => new AsyncUnaryResultMethodBuilder() { methodBuilder = AsyncTaskMethodBuilder.Create() }; + public static AsyncUnaryResultMethodBuilder Create() + => new AsyncUnaryResultMethodBuilder() { methodBuilder = AsyncTaskMethodBuilder.Create() }; - public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine - => methodBuilder.Start(ref stateMachine); + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + => methodBuilder.Start(ref stateMachine); - public void SetStateMachine(IAsyncStateMachine stateMachine) - => methodBuilder.SetStateMachine(stateMachine); + public void SetStateMachine(IAsyncStateMachine stateMachine) + => methodBuilder.SetStateMachine(stateMachine); - public void SetResult() + public void SetResult() + { + if (useBuilder) { - if (useBuilder) - { - methodBuilder.SetResult(Nil.Default); - } - else - { - hasResult = true; - } + methodBuilder.SetResult(Nil.Default); } + else + { + hasResult = true; + } + } - public void SetException(Exception ex) - => methodBuilder.SetException(ex); + public void SetException(Exception ex) + => methodBuilder.SetException(ex); - public UnaryResult Task + public UnaryResult Task + { + get { - get + if (hasResult) { - if (hasResult) - { - return new UnaryResult(Nil.Default); - } - - useBuilder = true; - return new UnaryResult(methodBuilder.Task); + return new UnaryResult(Nil.Default); } - } - public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : INotifyCompletion - where TStateMachine : IAsyncStateMachine - { useBuilder = true; - methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); + return new UnaryResult(methodBuilder.Task); } + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine - { - useBuilder = true; - methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); - } + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + useBuilder = true; + methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); } - public struct AsyncUnaryResultMethodBuilder + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine { - AsyncTaskMethodBuilder methodBuilder; - T result; - bool haveResult; - bool useBuilder; + useBuilder = true; + methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); + } +} - public static AsyncUnaryResultMethodBuilder Create() - { - return new AsyncUnaryResultMethodBuilder() { methodBuilder = AsyncTaskMethodBuilder.Create() }; - } +public struct AsyncUnaryResultMethodBuilder +{ + AsyncTaskMethodBuilder methodBuilder; + T result; + bool haveResult; + bool useBuilder; - public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + public static AsyncUnaryResultMethodBuilder Create() + { + return new AsyncUnaryResultMethodBuilder() { methodBuilder = AsyncTaskMethodBuilder.Create() }; + } + + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + methodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics + } + + public void SetStateMachine(IAsyncStateMachine stateMachine) + { + methodBuilder.SetStateMachine(stateMachine); + } + + public void SetResult(T result) + { + if (useBuilder) { - methodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics + methodBuilder.SetResult(result); } - - public void SetStateMachine(IAsyncStateMachine stateMachine) + else { - methodBuilder.SetStateMachine(stateMachine); + this.result = result; + haveResult = true; } + } - public void SetResult(T result) + public void SetException(Exception exception) + { + methodBuilder.SetException(exception); + } + + public UnaryResult Task + { + get { - if (useBuilder) + if (haveResult) { - methodBuilder.SetResult(result); + return new UnaryResult(result); } else { - this.result = result; - haveResult = true; - } - } - - public void SetException(Exception exception) - { - methodBuilder.SetException(exception); - } - - public UnaryResult Task - { - get - { - if (haveResult) - { - return new UnaryResult(result); - } - else - { - useBuilder = true; - return new UnaryResult(methodBuilder.Task); - } + useBuilder = true; + return new UnaryResult(methodBuilder.Task); } } + } - public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : INotifyCompletion - where TStateMachine : IAsyncStateMachine - { - useBuilder = true; - methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); - } + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + useBuilder = true; + methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); + } - [SecuritySafeCritical] - public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) - where TAwaiter : ICriticalNotifyCompletion - where TStateMachine : IAsyncStateMachine - { - useBuilder = true; - methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); - } + [SecuritySafeCritical] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + useBuilder = true; + methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); } } diff --git a/src/MagicOnion.Abstractions/DuplexStreamingResult.cs b/src/MagicOnion.Abstractions/DuplexStreamingResult.cs index 61537d3d5..b104d4c51 100644 --- a/src/MagicOnion.Abstractions/DuplexStreamingResult.cs +++ b/src/MagicOnion.Abstractions/DuplexStreamingResult.cs @@ -1,65 +1,64 @@ using Grpc.Core; using MagicOnion.Internal; -namespace MagicOnion +namespace MagicOnion; + +/// +/// Wrapped AsyncDuplexStreamingCall. +/// +public readonly struct DuplexStreamingResult : IDisposable { - /// - /// Wrapped AsyncDuplexStreamingCall. - /// - public readonly struct DuplexStreamingResult : IDisposable - { - readonly IAsyncDuplexStreamingCallWrapper inner; + readonly IAsyncDuplexStreamingCallWrapper inner; - public DuplexStreamingResult(IAsyncDuplexStreamingCallWrapper inner) - { - this.inner = inner; - } + public DuplexStreamingResult(IAsyncDuplexStreamingCallWrapper inner) + { + this.inner = inner; + } - /// - /// Async stream to read streaming responses. - /// - public IAsyncStreamReader ResponseStream - => inner.ResponseStream; + /// + /// Async stream to read streaming responses. + /// + public IAsyncStreamReader ResponseStream + => inner.ResponseStream; - /// - /// Async stream to send streaming requests. - /// - public IClientStreamWriter RequestStream - => inner.RequestStream; + /// + /// Async stream to send streaming requests. + /// + public IClientStreamWriter RequestStream + => inner.RequestStream; - /// - /// Asynchronous access to response headers. - /// - public Task ResponseHeadersAsync - => inner.ResponseHeadersAsync; + /// + /// Asynchronous access to response headers. + /// + public Task ResponseHeadersAsync + => inner.ResponseHeadersAsync; - /// - /// Gets the call status if the call has already finished. - /// Throws InvalidOperationException otherwise. - /// - public Status GetStatus() - => inner.GetStatus(); + /// + /// Gets the call status if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// + public Status GetStatus() + => inner.GetStatus(); - /// - /// Gets the call trailing metadata if the call has already finished. - /// Throws InvalidOperationException otherwise. - /// - public Metadata GetTrailers() - => inner.GetTrailers(); + /// + /// Gets the call trailing metadata if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// + public Metadata GetTrailers() + => inner.GetTrailers(); - /// - /// Provides means to cleanup after the call. - /// If the call has already finished normally (request stream has been completed and response stream has been fully read), doesn't do anything. - /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. - /// As a result, all resources being used by the call should be released eventually. - /// - /// - /// Normally, there is no need for you to dispose the call unless you want to utilize the - /// "Cancel" semantics of invoking Dispose. - /// - public void Dispose() - { - inner?.Dispose(); - } + /// + /// Provides means to cleanup after the call. + /// If the call has already finished normally (request stream has been completed and response stream has been fully read), doesn't do anything. + /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. + /// As a result, all resources being used by the call should be released eventually. + /// + /// + /// Normally, there is no need for you to dispose the call unless you want to utilize the + /// "Cancel" semantics of invoking Dispose. + /// + public void Dispose() + { + inner?.Dispose(); } } diff --git a/src/MagicOnion.Abstractions/DynamicArgumentTuple.cs b/src/MagicOnion.Abstractions/DynamicArgumentTuple.cs index 3cdd3a4c2..26074db82 100644 --- a/src/MagicOnion.Abstractions/DynamicArgumentTuple.cs +++ b/src/MagicOnion.Abstractions/DynamicArgumentTuple.cs @@ -1,857 +1,852 @@ using System.Runtime.InteropServices; using MessagePack; -namespace MagicOnion -{ - // T2 ~ T15 - // NOTE: Blazor WebAssembly (AOT) does not support more than 16 generic type parameters. - +namespace MagicOnion; +// T2 ~ T15 +// NOTE: Blazor WebAssembly (AOT) does not support more than 16 generic type parameters. - - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [Key(5)] - public readonly T6 Item6; + [Key(5)] + public readonly T6 Item6; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - Item6 = item6; + Item6 = item6; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [Key(5)] - public readonly T6 Item6; + [Key(5)] + public readonly T6 Item6; - [Key(6)] - public readonly T7 Item7; + [Key(6)] + public readonly T7 Item7; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - Item6 = item6; + Item6 = item6; - Item7 = item7; + Item7 = item7; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [Key(5)] - public readonly T6 Item6; + [Key(5)] + public readonly T6 Item6; - [Key(6)] - public readonly T7 Item7; + [Key(6)] + public readonly T7 Item7; - [Key(7)] - public readonly T8 Item8; + [Key(7)] + public readonly T8 Item8; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - Item6 = item6; + Item6 = item6; - Item7 = item7; + Item7 = item7; - Item8 = item8; + Item8 = item8; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [Key(5)] - public readonly T6 Item6; + [Key(5)] + public readonly T6 Item6; - [Key(6)] - public readonly T7 Item7; + [Key(6)] + public readonly T7 Item7; - [Key(7)] - public readonly T8 Item8; + [Key(7)] + public readonly T8 Item8; - [Key(8)] - public readonly T9 Item9; + [Key(8)] + public readonly T9 Item9; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - Item6 = item6; + Item6 = item6; - Item7 = item7; + Item7 = item7; - Item8 = item8; + Item8 = item8; - Item9 = item9; + Item9 = item9; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [Key(5)] - public readonly T6 Item6; + [Key(5)] + public readonly T6 Item6; - [Key(6)] - public readonly T7 Item7; + [Key(6)] + public readonly T7 Item7; - [Key(7)] - public readonly T8 Item8; + [Key(7)] + public readonly T8 Item8; - [Key(8)] - public readonly T9 Item9; + [Key(8)] + public readonly T9 Item9; - [Key(9)] - public readonly T10 Item10; + [Key(9)] + public readonly T10 Item10; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - Item6 = item6; + Item6 = item6; - Item7 = item7; + Item7 = item7; - Item8 = item8; + Item8 = item8; - Item9 = item9; + Item9 = item9; - Item10 = item10; + Item10 = item10; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [Key(5)] - public readonly T6 Item6; + [Key(5)] + public readonly T6 Item6; - [Key(6)] - public readonly T7 Item7; + [Key(6)] + public readonly T7 Item7; - [Key(7)] - public readonly T8 Item8; + [Key(7)] + public readonly T8 Item8; - [Key(8)] - public readonly T9 Item9; + [Key(8)] + public readonly T9 Item9; - [Key(9)] - public readonly T10 Item10; + [Key(9)] + public readonly T10 Item10; - [Key(10)] - public readonly T11 Item11; + [Key(10)] + public readonly T11 Item11; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10, T11 item11) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10, T11 item11) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - Item6 = item6; + Item6 = item6; - Item7 = item7; + Item7 = item7; - Item8 = item8; + Item8 = item8; - Item9 = item9; + Item9 = item9; - Item10 = item10; + Item10 = item10; - Item11 = item11; + Item11 = item11; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [Key(5)] - public readonly T6 Item6; + [Key(5)] + public readonly T6 Item6; - [Key(6)] - public readonly T7 Item7; + [Key(6)] + public readonly T7 Item7; - [Key(7)] - public readonly T8 Item8; + [Key(7)] + public readonly T8 Item8; - [Key(8)] - public readonly T9 Item9; + [Key(8)] + public readonly T9 Item9; - [Key(9)] - public readonly T10 Item10; + [Key(9)] + public readonly T10 Item10; - [Key(10)] - public readonly T11 Item11; + [Key(10)] + public readonly T11 Item11; - [Key(11)] - public readonly T12 Item12; + [Key(11)] + public readonly T12 Item12; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10, T11 item11, T12 item12) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10, T11 item11, T12 item12) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - Item6 = item6; + Item6 = item6; - Item7 = item7; + Item7 = item7; - Item8 = item8; + Item8 = item8; - Item9 = item9; + Item9 = item9; - Item10 = item10; + Item10 = item10; - Item11 = item11; + Item11 = item11; - Item12 = item12; + Item12 = item12; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [Key(5)] - public readonly T6 Item6; + [Key(5)] + public readonly T6 Item6; - [Key(6)] - public readonly T7 Item7; + [Key(6)] + public readonly T7 Item7; - [Key(7)] - public readonly T8 Item8; + [Key(7)] + public readonly T8 Item8; - [Key(8)] - public readonly T9 Item9; + [Key(8)] + public readonly T9 Item9; - [Key(9)] - public readonly T10 Item10; + [Key(9)] + public readonly T10 Item10; - [Key(10)] - public readonly T11 Item11; + [Key(10)] + public readonly T11 Item11; - [Key(11)] - public readonly T12 Item12; + [Key(11)] + public readonly T12 Item12; - [Key(12)] - public readonly T13 Item13; + [Key(12)] + public readonly T13 Item13; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10, T11 item11, T12 item12, T13 item13) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10, T11 item11, T12 item12, T13 item13) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - Item6 = item6; + Item6 = item6; - Item7 = item7; + Item7 = item7; - Item8 = item8; + Item8 = item8; - Item9 = item9; + Item9 = item9; - Item10 = item10; + Item10 = item10; - Item11 = item11; + Item11 = item11; - Item12 = item12; + Item12 = item12; - Item13 = item13; + Item13 = item13; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [Key(5)] - public readonly T6 Item6; + [Key(5)] + public readonly T6 Item6; - [Key(6)] - public readonly T7 Item7; + [Key(6)] + public readonly T7 Item7; - [Key(7)] - public readonly T8 Item8; + [Key(7)] + public readonly T8 Item8; - [Key(8)] - public readonly T9 Item9; + [Key(8)] + public readonly T9 Item9; - [Key(9)] - public readonly T10 Item10; + [Key(9)] + public readonly T10 Item10; - [Key(10)] - public readonly T11 Item11; + [Key(10)] + public readonly T11 Item11; - [Key(11)] - public readonly T12 Item12; + [Key(11)] + public readonly T12 Item12; - [Key(12)] - public readonly T13 Item13; + [Key(12)] + public readonly T13 Item13; - [Key(13)] - public readonly T14 Item14; + [Key(13)] + public readonly T14 Item14; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10, T11 item11, T12 item12, T13 item13, T14 item14) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10, T11 item11, T12 item12, T13 item13, T14 item14) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - Item6 = item6; + Item6 = item6; - Item7 = item7; + Item7 = item7; - Item8 = item8; + Item8 = item8; - Item9 = item9; + Item9 = item9; - Item10 = item10; + Item10 = item10; - Item11 = item11; + Item11 = item11; - Item12 = item12; + Item12 = item12; - Item13 = item13; + Item13 = item13; - Item14 = item14; + Item14 = item14; - } } +} - [MessagePackObject] - [StructLayout(LayoutKind.Auto)] +[MessagePackObject] +[StructLayout(LayoutKind.Auto)] #if MAGICONION_USE_REFTYPE_DYNAMICARGUMENTTUPLE public sealed class DynamicArgumentTuple #else - public struct DynamicArgumentTuple +public struct DynamicArgumentTuple #endif - { +{ - [Key(0)] - public readonly T1 Item1; + [Key(0)] + public readonly T1 Item1; - [Key(1)] - public readonly T2 Item2; + [Key(1)] + public readonly T2 Item2; - [Key(2)] - public readonly T3 Item3; + [Key(2)] + public readonly T3 Item3; - [Key(3)] - public readonly T4 Item4; + [Key(3)] + public readonly T4 Item4; - [Key(4)] - public readonly T5 Item5; + [Key(4)] + public readonly T5 Item5; - [Key(5)] - public readonly T6 Item6; + [Key(5)] + public readonly T6 Item6; - [Key(6)] - public readonly T7 Item7; + [Key(6)] + public readonly T7 Item7; - [Key(7)] - public readonly T8 Item8; + [Key(7)] + public readonly T8 Item8; - [Key(8)] - public readonly T9 Item9; + [Key(8)] + public readonly T9 Item9; - [Key(9)] - public readonly T10 Item10; + [Key(9)] + public readonly T10 Item10; - [Key(10)] - public readonly T11 Item11; + [Key(10)] + public readonly T11 Item11; - [Key(11)] - public readonly T12 Item12; + [Key(11)] + public readonly T12 Item12; - [Key(12)] - public readonly T13 Item13; + [Key(12)] + public readonly T13 Item13; - [Key(13)] - public readonly T14 Item14; + [Key(13)] + public readonly T14 Item14; - [Key(14)] - public readonly T15 Item15; + [Key(14)] + public readonly T15 Item15; - [SerializationConstructor] - public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10, T11 item11, T12 item12, T13 item13, T14 item14, T15 item15) - { + [SerializationConstructor] + public DynamicArgumentTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10, T11 item11, T12 item12, T13 item13, T14 item14, T15 item15) + { - Item1 = item1; + Item1 = item1; - Item2 = item2; + Item2 = item2; - Item3 = item3; + Item3 = item3; - Item4 = item4; + Item4 = item4; - Item5 = item5; + Item5 = item5; - Item6 = item6; + Item6 = item6; - Item7 = item7; + Item7 = item7; - Item8 = item8; + Item8 = item8; - Item9 = item9; + Item9 = item9; - Item10 = item10; + Item10 = item10; - Item11 = item11; + Item11 = item11; - Item12 = item12; + Item12 = item12; - Item13 = item13; + Item13 = item13; - Item14 = item14; + Item14 = item14; - Item15 = item15; + Item15 = item15; - } } - } diff --git a/src/MagicOnion.Abstractions/GenerateDefineDebugAttribute.cs b/src/MagicOnion.Abstractions/GenerateDefineDebugAttribute.cs index 57af85f59..d95e298fc 100644 --- a/src/MagicOnion.Abstractions/GenerateDefineDebugAttribute.cs +++ b/src/MagicOnion.Abstractions/GenerateDefineDebugAttribute.cs @@ -1,14 +1,13 @@ -namespace MagicOnion +namespace MagicOnion; + +/// +/// instruction for moc.exe, surround #if symbol with output code. +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] +[Obsolete("GenerateDefineDebug is no longer used from the generator. Use C# '#if' directive instead.")] +public class GenerateDefineDebugAttribute : Attribute { - /// - /// instruction for moc.exe, surround #if symbol with output code. - /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] - [Obsolete("GenerateDefineDebug is no longer used from the generator. Use C# '#if' directive instead.")] - public class GenerateDefineDebugAttribute : Attribute + public GenerateDefineDebugAttribute() { - public GenerateDefineDebugAttribute() - { - } } } diff --git a/src/MagicOnion.Abstractions/GenerateIfDirectiveAttribute.cs b/src/MagicOnion.Abstractions/GenerateIfDirectiveAttribute.cs index 6ff3b157a..ac09e9bcb 100644 --- a/src/MagicOnion.Abstractions/GenerateIfDirectiveAttribute.cs +++ b/src/MagicOnion.Abstractions/GenerateIfDirectiveAttribute.cs @@ -1,14 +1,13 @@ -namespace MagicOnion +namespace MagicOnion; + +/// +/// instruction for moc.exe, surround #if symbol with output code. +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] +[Obsolete("GenerateIfDirective is no longer used from the generator. Use C# '#if' directive instead.")] +public class GenerateIfDirectiveAttribute : Attribute { - /// - /// instruction for moc.exe, surround #if symbol with output code. - /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] - [Obsolete("GenerateIfDirective is no longer used from the generator. Use C# '#if' directive instead.")] - public class GenerateIfDirectiveAttribute : Attribute + public GenerateIfDirectiveAttribute(string condition) { - public GenerateIfDirectiveAttribute(string condition) - { - } } } diff --git a/src/MagicOnion.Abstractions/IService.cs b/src/MagicOnion.Abstractions/IService.cs index 02c4e000e..20e493d0e 100644 --- a/src/MagicOnion.Abstractions/IService.cs +++ b/src/MagicOnion.Abstractions/IService.cs @@ -1,19 +1,18 @@ using Grpc.Core; -namespace MagicOnion +namespace MagicOnion; + +// used for MagicOnionEngine assembly scan for boostup analyze speed. +public interface IServiceMarker { - // used for MagicOnionEngine assembly scan for boostup analyze speed. - public interface IServiceMarker - { - } +} - public interface IService : IServiceMarker - { - TSelf WithOptions(CallOptions option); - TSelf WithHeaders(Metadata headers); - TSelf WithDeadline(DateTime deadline); - TSelf WithCancellationToken(CancellationToken cancellationToken); - TSelf WithHost(string host); - } +public interface IService : IServiceMarker +{ + TSelf WithOptions(CallOptions option); + TSelf WithHeaders(Metadata headers); + TSelf WithDeadline(DateTime deadline); + TSelf WithCancellationToken(CancellationToken cancellationToken); + TSelf WithHost(string host); } diff --git a/src/MagicOnion.Abstractions/IStreamingHub.cs b/src/MagicOnion.Abstractions/IStreamingHub.cs index 8b9178642..7e351498a 100644 --- a/src/MagicOnion.Abstractions/IStreamingHub.cs +++ b/src/MagicOnion.Abstractions/IStreamingHub.cs @@ -1,13 +1,12 @@ -namespace MagicOnion +namespace MagicOnion; + +public interface IStreamingHubMarker { - public interface IStreamingHubMarker - { - } +} - public interface IStreamingHub : IStreamingHubMarker, IServiceMarker - { - TSelf FireAndForget(); // if changed to get-only property, intellisense does not work on VS2017. - Task DisposeAsync(); - Task WaitForDisconnect(); - } +public interface IStreamingHub : IStreamingHubMarker, IServiceMarker +{ + TSelf FireAndForget(); // if changed to get-only property, intellisense does not work on VS2017. + Task DisposeAsync(); + Task WaitForDisconnect(); } diff --git a/src/MagicOnion.Abstractions/IgnoreAttribute.cs b/src/MagicOnion.Abstractions/IgnoreAttribute.cs index db16050d1..b63682304 100644 --- a/src/MagicOnion.Abstractions/IgnoreAttribute.cs +++ b/src/MagicOnion.Abstractions/IgnoreAttribute.cs @@ -1,10 +1,9 @@ -namespace MagicOnion +namespace MagicOnion; + +/// +/// Don't register on MagicOnionEngine. +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false,Inherited = false)] +public class IgnoreAttribute : Attribute { - /// - /// Don't register on MagicOnionEngine. - /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false,Inherited = false)] - public class IgnoreAttribute : Attribute - { - } } diff --git a/src/MagicOnion.Abstractions/Internal/Box.cs b/src/MagicOnion.Abstractions/Internal/Box.cs index d48e43998..6f6e44835 100644 --- a/src/MagicOnion.Abstractions/Internal/Box.cs +++ b/src/MagicOnion.Abstractions/Internal/Box.cs @@ -1,52 +1,51 @@ using System.ComponentModel; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +// Pubternal API +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed class Box : IEquatable> { - // Pubternal API - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Box : IEquatable> + public readonly T Value; + + internal Box(T value) { - public readonly T Value; - - internal Box(T value) - { - Value = value; - } - - public bool Equals(Box? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return EqualityComparer.Default.Equals(Value, other.Value); - } - - public override bool Equals(object? obj) - { - return ReferenceEquals(this, obj) || obj is Box other && Equals(other); - } - - public override int GetHashCode() - { - return EqualityComparer.Default.GetHashCode(Value!); - } - - public static bool operator ==(Box valueA, Box valueB) - => object.ReferenceEquals(valueA, null) ? object.ReferenceEquals(valueB, null) : valueA.Equals(valueB); - - public static bool operator !=(Box valueA, Box valueB) - => !(valueA == valueB); + Value = value; } - [EditorBrowsable(EditorBrowsableState.Never)] - public static class Box + public bool Equals(Box? other) { - private static readonly Box Nil = new Box(MessagePack.Nil.Default); - private static readonly Box BoolTrue = new Box(true); - private static readonly Box BoolFalse = new Box(false); - - public static Box Create(T value) - => (value is MessagePack.Nil) ? (Box)(object)Nil - : (value is bool b) ? (Box)(object)(b ? BoolTrue : BoolFalse) - : new Box(value); + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return EqualityComparer.Default.Equals(Value, other.Value); } + + public override bool Equals(object? obj) + { + return ReferenceEquals(this, obj) || obj is Box other && Equals(other); + } + + public override int GetHashCode() + { + return EqualityComparer.Default.GetHashCode(Value!); + } + + public static bool operator ==(Box valueA, Box valueB) + => object.ReferenceEquals(valueA, null) ? object.ReferenceEquals(valueB, null) : valueA.Equals(valueB); + + public static bool operator !=(Box valueA, Box valueB) + => !(valueA == valueB); +} + +[EditorBrowsable(EditorBrowsableState.Never)] +public static class Box +{ + private static readonly Box Nil = new Box(MessagePack.Nil.Default); + private static readonly Box BoolTrue = new Box(true); + private static readonly Box BoolFalse = new Box(false); + + public static Box Create(T value) + => (value is MessagePack.Nil) ? (Box)(object)Nil + : (value is bool b) ? (Box)(object)(b ? BoolTrue : BoolFalse) + : new Box(value); } diff --git a/src/MagicOnion.Abstractions/Internal/IAsyncGrpcCallWrapper.cs b/src/MagicOnion.Abstractions/Internal/IAsyncGrpcCallWrapper.cs index 6230555db..1f404ec31 100644 --- a/src/MagicOnion.Abstractions/Internal/IAsyncGrpcCallWrapper.cs +++ b/src/MagicOnion.Abstractions/Internal/IAsyncGrpcCallWrapper.cs @@ -1,28 +1,27 @@ using Grpc.Core; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +public interface IAsyncGrpcCallWrapper : IDisposable { - public interface IAsyncGrpcCallWrapper : IDisposable - { - Task ResponseHeadersAsync { get; } - Status GetStatus(); - Metadata GetTrailers(); - } + Task ResponseHeadersAsync { get; } + Status GetStatus(); + Metadata GetTrailers(); +} - public interface IAsyncClientStreamingCallWrapper : IAsyncGrpcCallWrapper - { - IClientStreamWriter RequestStream { get; } - Task ResponseAsync { get; } - } +public interface IAsyncClientStreamingCallWrapper : IAsyncGrpcCallWrapper +{ + IClientStreamWriter RequestStream { get; } + Task ResponseAsync { get; } +} - public interface IAsyncServerStreamingCallWrapper : IAsyncGrpcCallWrapper - { - IAsyncStreamReader ResponseStream { get; } - } +public interface IAsyncServerStreamingCallWrapper : IAsyncGrpcCallWrapper +{ + IAsyncStreamReader ResponseStream { get; } +} - public interface IAsyncDuplexStreamingCallWrapper : IAsyncGrpcCallWrapper - { - IClientStreamWriter RequestStream { get; } - IAsyncStreamReader ResponseStream { get; } - } +public interface IAsyncDuplexStreamingCallWrapper : IAsyncGrpcCallWrapper +{ + IClientStreamWriter RequestStream { get; } + IAsyncStreamReader ResponseStream { get; } } diff --git a/src/MagicOnion.Abstractions/Internal/RawBytesBox.cs b/src/MagicOnion.Abstractions/Internal/RawBytesBox.cs index 1abb3365d..e5d556847 100644 --- a/src/MagicOnion.Abstractions/Internal/RawBytesBox.cs +++ b/src/MagicOnion.Abstractions/Internal/RawBytesBox.cs @@ -1,16 +1,15 @@ using System.ComponentModel; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +// Pubternal API +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed class RawBytesBox { - // Pubternal API - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class RawBytesBox - { - public ReadOnlyMemory Bytes { get; } + public ReadOnlyMemory Bytes { get; } - public RawBytesBox(ReadOnlyMemory bytes) - { - Bytes = bytes; - } + public RawBytesBox(ReadOnlyMemory bytes) + { + Bytes = bytes; } } diff --git a/src/MagicOnion.Abstractions/Serialization/MagicOnionSerializer.cs b/src/MagicOnion.Abstractions/Serialization/MagicOnionSerializer.cs index 900972837..07d1fbc48 100644 --- a/src/MagicOnion.Abstractions/Serialization/MagicOnionSerializer.cs +++ b/src/MagicOnion.Abstractions/Serialization/MagicOnionSerializer.cs @@ -2,28 +2,27 @@ using System.Reflection; using Grpc.Core; -namespace MagicOnion.Serialization +namespace MagicOnion.Serialization; + +/// +/// Provides a serializer for request/response of MagicOnion services and hub methods. +/// +public interface IMagicOnionSerializerProvider { /// - /// Provides a serializer for request/response of MagicOnion services and hub methods. + /// Create a serializer for the service method. /// - public interface IMagicOnionSerializerProvider - { - /// - /// Create a serializer for the service method. - /// - /// gRPC method type of the method. - /// A method info for an implementation of the service method. It is a hint that handling request parameters on the server, which may be passed null on the client. - /// - IMagicOnionSerializer Create(MethodType methodType, MethodInfo? methodInfo); - } + /// gRPC method type of the method. + /// A method info for an implementation of the service method. It is a hint that handling request parameters on the server, which may be passed null on the client. + /// + IMagicOnionSerializer Create(MethodType methodType, MethodInfo? methodInfo); +} - /// - /// Provides a processing for message serialization. - /// - public interface IMagicOnionSerializer - { - void Serialize(IBufferWriter writer, in T value); - T Deserialize(in ReadOnlySequence bytes); - } +/// +/// Provides a processing for message serialization. +/// +public interface IMagicOnionSerializer +{ + void Serialize(IBufferWriter writer, in T value); + T Deserialize(in ReadOnlySequence bytes); } diff --git a/src/MagicOnion.Abstractions/Server/Hubs/MethodIdAttribute.cs b/src/MagicOnion.Abstractions/Server/Hubs/MethodIdAttribute.cs index 202ca1b63..7a28eb5a2 100644 --- a/src/MagicOnion.Abstractions/Server/Hubs/MethodIdAttribute.cs +++ b/src/MagicOnion.Abstractions/Server/Hubs/MethodIdAttribute.cs @@ -1,13 +1,12 @@ -namespace MagicOnion.Server.Hubs +namespace MagicOnion.Server.Hubs; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] +public class MethodIdAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] - public class MethodIdAttribute : Attribute - { - public readonly int MethodId; + public readonly int MethodId; - public MethodIdAttribute(int methodId) - { - MethodId = methodId; - } + public MethodIdAttribute(int methodId) + { + MethodId = methodId; } } diff --git a/src/MagicOnion.Abstractions/ServerStreamingResult.cs b/src/MagicOnion.Abstractions/ServerStreamingResult.cs index cc0c28649..de3a6ed45 100644 --- a/src/MagicOnion.Abstractions/ServerStreamingResult.cs +++ b/src/MagicOnion.Abstractions/ServerStreamingResult.cs @@ -1,57 +1,56 @@ using Grpc.Core; using MagicOnion.Internal; -namespace MagicOnion +namespace MagicOnion; + +/// +/// Wrapped AsyncServerStreamingCall. +/// +public readonly struct ServerStreamingResult : IDisposable { - /// - /// Wrapped AsyncServerStreamingCall. - /// - public readonly struct ServerStreamingResult : IDisposable + readonly IAsyncServerStreamingCallWrapper inner; + + public ServerStreamingResult(IAsyncServerStreamingCallWrapper inner) { - readonly IAsyncServerStreamingCallWrapper inner; - - public ServerStreamingResult(IAsyncServerStreamingCallWrapper inner) - { - this.inner = inner; - } - - /// - /// Async stream to read streaming responses. - /// - public IAsyncStreamReader ResponseStream - => inner.ResponseStream; - - /// - /// Asynchronous access to response headers. - /// - public Task ResponseHeadersAsync - => inner.ResponseHeadersAsync; - - /// - /// Gets the call status if the call has already finished. - /// Throws InvalidOperationException otherwise. - /// - public Status GetStatus() - => inner.GetStatus(); - - /// - /// Gets the call trailing metadata if the call has already finished. - /// Throws InvalidOperationException otherwise. - /// - public Metadata GetTrailers() - => inner.GetTrailers(); - - /// - /// Provides means to cleanup after the call. - /// If the call has already finished normally (response stream has been fully read), doesn't do anything. - /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. - /// As a result, all resources being used by the call should be released eventually. - /// - /// - /// Normally, there is no need for you to dispose the call unless you want to utilize the - /// "Cancel" semantics of invoking Dispose. - /// - public void Dispose() - => inner?.Dispose(); + this.inner = inner; } + + /// + /// Async stream to read streaming responses. + /// + public IAsyncStreamReader ResponseStream + => inner.ResponseStream; + + /// + /// Asynchronous access to response headers. + /// + public Task ResponseHeadersAsync + => inner.ResponseHeadersAsync; + + /// + /// Gets the call status if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// + public Status GetStatus() + => inner.GetStatus(); + + /// + /// Gets the call trailing metadata if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// + public Metadata GetTrailers() + => inner.GetTrailers(); + + /// + /// Provides means to cleanup after the call. + /// If the call has already finished normally (response stream has been fully read), doesn't do anything. + /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. + /// As a result, all resources being used by the call should be released eventually. + /// + /// + /// Normally, there is no need for you to dispose the call unless you want to utilize the + /// "Cancel" semantics of invoking Dispose. + /// + public void Dispose() + => inner?.Dispose(); } diff --git a/src/MagicOnion.Abstractions/UnaryResult.cs b/src/MagicOnion.Abstractions/UnaryResult.cs index c3367c177..b16464d10 100644 --- a/src/MagicOnion.Abstractions/UnaryResult.cs +++ b/src/MagicOnion.Abstractions/UnaryResult.cs @@ -4,332 +4,331 @@ using System.Runtime.CompilerServices; using MessagePack; -namespace MagicOnion +namespace MagicOnion; + +/// +/// Represents the result of a Unary call that wraps AsyncUnaryCall as Task-like. +/// +[AsyncMethodBuilder(typeof(AsyncUnaryResultMethodBuilder))] +public readonly struct UnaryResult { - /// - /// Represents the result of a Unary call that wraps AsyncUnaryCall as Task-like. - /// - [AsyncMethodBuilder(typeof(AsyncUnaryResultMethodBuilder))] - public readonly struct UnaryResult - { - internal readonly bool hasRawValue; - internal readonly Task? rawTaskValue; - internal readonly Task>? response; + internal readonly bool hasRawValue; + internal readonly Task? rawTaskValue; + internal readonly Task>? response; - public UnaryResult(Nil nil) - { - this.hasRawValue = true; - this.rawTaskValue = default; - this.response = null; - } + public UnaryResult(Nil nil) + { + this.hasRawValue = true; + this.rawTaskValue = default; + this.response = null; + } - public UnaryResult(Task rawTaskValue) - { - this.hasRawValue = true; - this.rawTaskValue = rawTaskValue ?? throw new ArgumentNullException(nameof(rawTaskValue)); - this.response = null; - } + public UnaryResult(Task rawTaskValue) + { + this.hasRawValue = true; + this.rawTaskValue = rawTaskValue ?? throw new ArgumentNullException(nameof(rawTaskValue)); + this.response = null; + } - public UnaryResult(Task> response) - { - this.hasRawValue = false; - this.rawTaskValue = default; - this.response = response ?? throw new ArgumentNullException(nameof(response)); - } + public UnaryResult(Task> response) + { + this.hasRawValue = false; + this.rawTaskValue = default; + this.response = response ?? throw new ArgumentNullException(nameof(response)); + } - /// - /// Asynchronous call result. - /// - public Task ResponseAsync + /// + /// Asynchronous call result. + /// + public Task ResponseAsync + { + get { - get + if (hasRawValue) { - if (hasRawValue) + if (rawTaskValue != null) { - if (rawTaskValue != null) - { - return rawTaskValue; - } + return rawTaskValue; } - else + } + else + { + // If the UnaryResult has no raw-value and no response, it is the default value of UnaryResult. + // So, we will return the default value of TResponse as Task. + if (response is null) { - // If the UnaryResult has no raw-value and no response, it is the default value of UnaryResult. - // So, we will return the default value of TResponse as Task. - if (response is null) - { - return Task.CompletedTask; - } - - return UnwrapResponse(); + return Task.CompletedTask; } - return Task.CompletedTask; + return UnwrapResponse(); } + + return Task.CompletedTask; } + } - /// - /// Asynchronous access to response headers. - /// - public Task ResponseHeadersAsync => UnwrapResponseHeaders(); + /// + /// Asynchronous access to response headers. + /// + public Task ResponseHeadersAsync => UnwrapResponseHeaders(); - Task> GetRequiredResponse() - => response ?? throw new InvalidOperationException("UnaryResult has no response."); + Task> GetRequiredResponse() + => response ?? throw new InvalidOperationException("UnaryResult has no response."); - async Task UnwrapResponse() - { - var ctx = await GetRequiredResponse().ConfigureAwait(false); - await ctx.ResponseAsync.ConfigureAwait(false); - } + async Task UnwrapResponse() + { + var ctx = await GetRequiredResponse().ConfigureAwait(false); + await ctx.ResponseAsync.ConfigureAwait(false); + } - async Task UnwrapResponseHeaders() + async Task UnwrapResponseHeaders() + { + var ctx = await GetRequiredResponse().ConfigureAwait(false); + return await ctx.ResponseHeadersAsync.ConfigureAwait(false); + } + + IResponseContext TryUnwrap() + { + var response = GetRequiredResponse(); + if (!response.IsCompleted) { - var ctx = await GetRequiredResponse().ConfigureAwait(false); - return await ctx.ResponseHeadersAsync.ConfigureAwait(false); + throw new InvalidOperationException("UnaryResult request is not yet completed, please await before call this."); } - IResponseContext TryUnwrap() + return response.Result; + } + + /// + /// Allows awaiting this object directly. + /// + public TaskAwaiter GetAwaiter() + => ResponseAsync.GetAwaiter(); + + /// + /// Gets the call status if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// + public Status GetStatus() + => TryUnwrap().GetStatus(); + + /// + /// Gets the call trailing metadata if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// + public Metadata GetTrailers() + => TryUnwrap().GetTrailers(); + + /// + /// Provides means to cleanup after the call. + /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything. + /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. + /// As a result, all resources being used by the call should be released eventually. + /// + /// + /// Normally, there is no need for you to dispose the call unless you want to utilize the + /// "Cancel" semantics of invoking Dispose. + /// + public void Dispose() + { + if (response is not null) { - var response = GetRequiredResponse(); if (!response.IsCompleted) { - throw new InvalidOperationException("UnaryResult request is not yet completed, please await before call this."); + UnwrapDispose(); } - - return response.Result; - } - - /// - /// Allows awaiting this object directly. - /// - public TaskAwaiter GetAwaiter() - => ResponseAsync.GetAwaiter(); - - /// - /// Gets the call status if the call has already finished. - /// Throws InvalidOperationException otherwise. - /// - public Status GetStatus() - => TryUnwrap().GetStatus(); - - /// - /// Gets the call trailing metadata if the call has already finished. - /// Throws InvalidOperationException otherwise. - /// - public Metadata GetTrailers() - => TryUnwrap().GetTrailers(); - - /// - /// Provides means to cleanup after the call. - /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything. - /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. - /// As a result, all resources being used by the call should be released eventually. - /// - /// - /// Normally, there is no need for you to dispose the call unless you want to utilize the - /// "Cancel" semantics of invoking Dispose. - /// - public void Dispose() - { - if (response is not null) + else { - if (!response.IsCompleted) - { - UnwrapDispose(); - } - else - { - response.Result.Dispose(); - } + response.Result.Dispose(); } } + } - async void UnwrapDispose() + async void UnwrapDispose() + { + try + { + var ctx = await GetRequiredResponse().ConfigureAwait(false); + ctx.Dispose(); + } + catch { - try - { - var ctx = await GetRequiredResponse().ConfigureAwait(false); - ctx.Dispose(); - } - catch - { - } } - - /// - /// Gets a completed with the void result. - /// - public static UnaryResult CompletedResult => default; - - /// - /// Creates a with the specified result. - /// - public static UnaryResult FromResult(T value) - => new UnaryResult(value); - - /// - /// Creates a with the specified result task. - /// - public static UnaryResult FromResult(Task task) - => new UnaryResult(task); - - /// - /// Gets the result that contains as the result value. - /// - [Obsolete("Use `UnaryResult` or `UnaryResult.FromResult(Nil.Default)` instead.")] - public static UnaryResult Nil - => new UnaryResult(MessagePack.Nil.Default); } /// - /// Represents the result of a Unary call that wraps AsyncUnaryCall as Task-like. + /// Gets a completed with the void result. /// - [AsyncMethodBuilder(typeof(AsyncUnaryResultMethodBuilder<>))] - public readonly struct UnaryResult - { - internal readonly bool hasRawValue; // internal - internal readonly TResponse? rawValue; // internal - internal readonly Task? rawTaskValue; // internal + public static UnaryResult CompletedResult => default; - readonly Task>? response; + /// + /// Creates a with the specified result. + /// + public static UnaryResult FromResult(T value) + => new UnaryResult(value); - public UnaryResult(TResponse rawValue) - { - this.hasRawValue = true; - this.rawValue = rawValue; - this.rawTaskValue = null; - this.response = null; - } + /// + /// Creates a with the specified result task. + /// + public static UnaryResult FromResult(Task task) + => new UnaryResult(task); - public UnaryResult(Task rawTaskValue) - { - this.hasRawValue = true; - this.rawValue = default(TResponse); - this.rawTaskValue = rawTaskValue ?? throw new ArgumentNullException(nameof(rawTaskValue)); - this.response = null; - } + /// + /// Gets the result that contains as the result value. + /// + [Obsolete("Use `UnaryResult` or `UnaryResult.FromResult(Nil.Default)` instead.")] + public static UnaryResult Nil + => new UnaryResult(MessagePack.Nil.Default); +} - public UnaryResult(Task> response) - { - this.hasRawValue = false; - this.rawValue = default(TResponse); - this.rawTaskValue = null; - this.response = response ?? throw new ArgumentNullException(nameof(response)); - } +/// +/// Represents the result of a Unary call that wraps AsyncUnaryCall as Task-like. +/// +[AsyncMethodBuilder(typeof(AsyncUnaryResultMethodBuilder<>))] +public readonly struct UnaryResult +{ + internal readonly bool hasRawValue; // internal + internal readonly TResponse? rawValue; // internal + internal readonly Task? rawTaskValue; // internal - /// - /// Asynchronous call result. - /// - public Task ResponseAsync + readonly Task>? response; + + public UnaryResult(TResponse rawValue) + { + this.hasRawValue = true; + this.rawValue = rawValue; + this.rawTaskValue = null; + this.response = null; + } + + public UnaryResult(Task rawTaskValue) + { + this.hasRawValue = true; + this.rawValue = default(TResponse); + this.rawTaskValue = rawTaskValue ?? throw new ArgumentNullException(nameof(rawTaskValue)); + this.response = null; + } + + public UnaryResult(Task> response) + { + this.hasRawValue = false; + this.rawValue = default(TResponse); + this.rawTaskValue = null; + this.response = response ?? throw new ArgumentNullException(nameof(response)); + } + + /// + /// Asynchronous call result. + /// + public Task ResponseAsync + { + get { - get + if (!hasRawValue) { - if (!hasRawValue) - { - // If the UnaryResult has no raw-value and no response, it is the default value of UnaryResult. - // So, we will return the default value of TResponse as Task. - if (response is null) - { - return Task.FromResult(default(TResponse)!); - } - - return UnwrapResponse(); - } - else if (rawTaskValue is not null) - { - return rawTaskValue; - } - else + // If the UnaryResult has no raw-value and no response, it is the default value of UnaryResult. + // So, we will return the default value of TResponse as Task. + if (response is null) { - return Task.FromResult(rawValue!); + return Task.FromResult(default(TResponse)!); } + + return UnwrapResponse(); + } + else if (rawTaskValue is not null) + { + return rawTaskValue; + } + else + { + return Task.FromResult(rawValue!); } } + } - /// - /// Asynchronous access to response headers. - /// - public Task ResponseHeadersAsync => UnwrapResponseHeaders(); + /// + /// Asynchronous access to response headers. + /// + public Task ResponseHeadersAsync => UnwrapResponseHeaders(); - Task> GetRequiredResponse() - => response ?? throw new InvalidOperationException("UnaryResult has no response."); + Task> GetRequiredResponse() + => response ?? throw new InvalidOperationException("UnaryResult has no response."); - async Task UnwrapResponse() + async Task UnwrapResponse() + { + var ctx = await GetRequiredResponse().ConfigureAwait(false); + return await ctx.ResponseAsync.ConfigureAwait(false); + } + + async Task UnwrapResponseHeaders() + { + var ctx = await GetRequiredResponse().ConfigureAwait(false); + return await ctx.ResponseHeadersAsync.ConfigureAwait(false); + } + + async void UnwrapDispose() + { + try { var ctx = await GetRequiredResponse().ConfigureAwait(false); - return await ctx.ResponseAsync.ConfigureAwait(false); + ctx.Dispose(); } - - async Task UnwrapResponseHeaders() + catch { - var ctx = await GetRequiredResponse().ConfigureAwait(false); - return await ctx.ResponseHeadersAsync.ConfigureAwait(false); } + } - async void UnwrapDispose() + IResponseContext TryUnwrap() + { + var response = GetRequiredResponse(); + if (!response.IsCompleted) { - try - { - var ctx = await GetRequiredResponse().ConfigureAwait(false); - ctx.Dispose(); - } - catch - { - } + throw new InvalidOperationException("UnaryResult request is not yet completed, please await before call this."); } - IResponseContext TryUnwrap() + return response.Result; + } + + /// + /// Allows awaiting this object directly. + /// + public TaskAwaiter GetAwaiter() + => ResponseAsync.GetAwaiter(); + + /// + /// Gets the call status if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// + public Status GetStatus() + => TryUnwrap().GetStatus(); + + /// + /// Gets the call trailing metadata if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// + public Metadata GetTrailers() + => TryUnwrap().GetTrailers(); + + /// + /// Provides means to cleanup after the call. + /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything. + /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. + /// As a result, all resources being used by the call should be released eventually. + /// + /// + /// Normally, there is no need for you to dispose the call unless you want to utilize the + /// "Cancel" semantics of invoking Dispose. + /// + public void Dispose() + { + if (response is not null) { - var response = GetRequiredResponse(); if (!response.IsCompleted) { - throw new InvalidOperationException("UnaryResult request is not yet completed, please await before call this."); + UnwrapDispose(); } - - return response.Result; - } - - /// - /// Allows awaiting this object directly. - /// - public TaskAwaiter GetAwaiter() - => ResponseAsync.GetAwaiter(); - - /// - /// Gets the call status if the call has already finished. - /// Throws InvalidOperationException otherwise. - /// - public Status GetStatus() - => TryUnwrap().GetStatus(); - - /// - /// Gets the call trailing metadata if the call has already finished. - /// Throws InvalidOperationException otherwise. - /// - public Metadata GetTrailers() - => TryUnwrap().GetTrailers(); - - /// - /// Provides means to cleanup after the call. - /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything. - /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. - /// As a result, all resources being used by the call should be released eventually. - /// - /// - /// Normally, there is no need for you to dispose the call unless you want to utilize the - /// "Cancel" semantics of invoking Dispose. - /// - public void Dispose() - { - if (response is not null) + else { - if (!response.IsCompleted) - { - UnwrapDispose(); - } - else - { - response.Result.Dispose(); - } + response.Result.Dispose(); } } } diff --git a/src/MagicOnion.Client/ClientFilter.cs b/src/MagicOnion.Client/ClientFilter.cs index f6305b7a0..87100075f 100644 --- a/src/MagicOnion.Client/ClientFilter.cs +++ b/src/MagicOnion.Client/ClientFilter.cs @@ -1,7 +1,6 @@ -namespace MagicOnion.Client +namespace MagicOnion.Client; + +public interface IClientFilter { - public interface IClientFilter - { - ValueTask SendAsync(RequestContext context, Func> next); - } + ValueTask SendAsync(RequestContext context, Func> next); } diff --git a/src/MagicOnion.Client/ClientHeartbeatEvent.cs b/src/MagicOnion.Client/ClientHeartbeatEvent.cs index 4110ae615..c8532dfc4 100644 --- a/src/MagicOnion.Client/ClientHeartbeatEvent.cs +++ b/src/MagicOnion.Client/ClientHeartbeatEvent.cs @@ -1,18 +1,17 @@ -namespace MagicOnion.Client +namespace MagicOnion.Client; + +/// +/// Represents a client heartbeat received event. +/// +public readonly struct ClientHeartbeatEvent { /// - /// Represents a client heartbeat received event. + /// Gets the round trip time (RTT) between client and server. /// - public readonly struct ClientHeartbeatEvent - { - /// - /// Gets the round trip time (RTT) between client and server. - /// - public TimeSpan RoundTripTime { get; } + public TimeSpan RoundTripTime { get; } - public ClientHeartbeatEvent(long roundTripTimeMs) - { - RoundTripTime = TimeSpan.FromMilliseconds(roundTripTimeMs); - } + public ClientHeartbeatEvent(long roundTripTimeMs) + { + RoundTripTime = TimeSpan.FromMilliseconds(roundTripTimeMs); } } diff --git a/src/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs b/src/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs index 3c0343c02..e590872dd 100644 --- a/src/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs +++ b/src/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs @@ -1,25 +1,25 @@ using System.Diagnostics.CodeAnalysis; using MagicOnion.Internal.Reflection; -namespace MagicOnion.Client.DynamicClient -{ - [RequiresUnreferencedCode(nameof(DynamicClientAssemblyHolder) + " is incompatible with trimming and Native AOT.")] +namespace MagicOnion.Client.DynamicClient; + +[RequiresUnreferencedCode(nameof(DynamicClientAssemblyHolder) + " is incompatible with trimming and Native AOT.")] #if ENABLE_SAVE_ASSEMBLY public #else - internal +internal #endif - static class DynamicClientAssemblyHolder - { - public const string ModuleName = "MagicOnion.Client.DynamicClient"; + static class DynamicClientAssemblyHolder +{ + public const string ModuleName = "MagicOnion.Client.DynamicClient"; - readonly static DynamicAssembly assembly; - public static DynamicAssembly Assembly { get { return assembly; } } + readonly static DynamicAssembly assembly; + public static DynamicAssembly Assembly { get { return assembly; } } - static DynamicClientAssemblyHolder() - { - assembly = new DynamicAssembly(ModuleName); - } + static DynamicClientAssemblyHolder() + { + assembly = new DynamicAssembly(ModuleName); + } #if ENABLE_SAVE_ASSEMBLY @@ -29,5 +29,4 @@ public static AssemblyBuilder Save() } #endif - } } diff --git a/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs b/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs index 60b433997..c5a3c7c8a 100644 --- a/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs +++ b/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs @@ -6,280 +6,279 @@ using MagicOnion.Serialization; using MessagePack; -namespace MagicOnion.Client.DynamicClient +namespace MagicOnion.Client.DynamicClient; + +internal class DynamicClientBuilder { - internal class DynamicClientBuilder + protected static class KnownTypes { - protected static class KnownTypes - { - public static Type[] ClientConstructorParameters { get; } = new[] { typeof(MagicOnionClientOptions), typeof(IMagicOnionSerializerProvider) }; - public static Type[] ClientCoreConstructorParameters { get; } = new[] { typeof(IMagicOnionSerializerProvider) }; - } + public static Type[] ClientConstructorParameters { get; } = new[] { typeof(MagicOnionClientOptions), typeof(IMagicOnionSerializerProvider) }; + public static Type[] ClientCoreConstructorParameters { get; } = new[] { typeof(IMagicOnionSerializerProvider) }; } +} - [RequiresUnreferencedCode(nameof(DynamicClientBuilder) + " is incompatible with trimming and Native AOT.")] - internal class DynamicClientBuilder : DynamicClientBuilder - where T : IService - { - public static Type ClientType { get; } = Build(); +[RequiresUnreferencedCode(nameof(DynamicClientBuilder) + " is incompatible with trimming and Native AOT.")] +internal class DynamicClientBuilder : DynamicClientBuilder + where T : IService +{ + public static Type ClientType { get; } = Build(); - static Type Build() - { - var serviceClientDefinition = ServiceClientDefinition.CreateFromType(); - var buildContext = new ServiceClientBuildContext(serviceClientDefinition); + static Type Build() + { + var serviceClientDefinition = ServiceClientDefinition.CreateFromType(); + var buildContext = new ServiceClientBuildContext(serviceClientDefinition); - EmitServiceClientClass(buildContext); + EmitServiceClientClass(buildContext); - return buildContext.ServiceClientType.CreateTypeInfo()!; - } + return buildContext.ServiceClientType.CreateTypeInfo()!; + } - class ServiceClientBuildContext + class ServiceClientBuildContext + { + public ServiceClientBuildContext(ServiceClientDefinition definition) { - public ServiceClientBuildContext(ServiceClientDefinition definition) - { - Definition = definition; - } + Definition = definition; + } - public ServiceClientDefinition Definition { get; } + public ServiceClientDefinition Definition { get; } - public TypeBuilder ClientCoreType { get; set; } = default!; // {ServiceName}Client+ClientCore - public ConstructorBuilder ClientCoreConstructor { get; set; } = default!; // {ServiceName}Client+ClientCore..ctor + public TypeBuilder ClientCoreType { get; set; } = default!; // {ServiceName}Client+ClientCore + public ConstructorBuilder ClientCoreConstructor { get; set; } = default!; // {ServiceName}Client+ClientCore..ctor - public TypeBuilder ServiceClientType { get; set; } = default!; // {ServiceName}Client - public ConstructorBuilder ServiceClientConstructor { get; set; } = default!; // {ServiceName}Client..ctor - public ConstructorBuilder ServiceClientConstructorForClone { get; set; } = default!; // {ServiceName}Client..ctor - public FieldBuilder FieldCore { get; set; } = default!; + public TypeBuilder ServiceClientType { get; set; } = default!; // {ServiceName}Client + public ConstructorBuilder ServiceClientConstructor { get; set; } = default!; // {ServiceName}Client..ctor + public ConstructorBuilder ServiceClientConstructorForClone { get; set; } = default!; // {ServiceName}Client..ctor + public FieldBuilder FieldCore { get; set; } = default!; - public Dictionary FieldAndMethodInvokerTypeByMethod { get; } = new Dictionary(); - } + public Dictionary FieldAndMethodInvokerTypeByMethod { get; } = new Dictionary(); + } - static void EmitServiceClientClass(ServiceClientBuildContext ctx) + static void EmitServiceClientClass(ServiceClientBuildContext ctx) + { + var constructedBaseClientType = typeof(MagicOnionClientBase<>).MakeGenericType(ctx.Definition.ServiceInterfaceType); + // [Ignore] + // public class {ServiceName}Client : ClientBase<{ServiceName}> + // { + // + ctx.ServiceClientType = DynamicClientAssemblyHolder.Assembly.DefineType($"MagicOnion.DynamicallyGeneratedClient.{ctx.Definition.ServiceInterfaceType.Namespace}.{ctx.Definition.ServiceInterfaceType.Name}Client", TypeAttributes.Public | TypeAttributes.Sealed, constructedBaseClientType, new[] { ctx.Definition.ServiceInterfaceType }); + // Set `IgnoreAttribute` to the generated client type. Hides generated-types from building MagicOnion service definitions. + ctx.ServiceClientType.SetCustomAttribute(new CustomAttributeBuilder(typeof(IgnoreAttribute).GetConstructor(Type.EmptyTypes)!, Array.Empty())); { - var constructedBaseClientType = typeof(MagicOnionClientBase<>).MakeGenericType(ctx.Definition.ServiceInterfaceType); - // [Ignore] - // public class {ServiceName}Client : ClientBase<{ServiceName}> - // { - // - ctx.ServiceClientType = DynamicClientAssemblyHolder.Assembly.DefineType($"MagicOnion.DynamicallyGeneratedClient.{ctx.Definition.ServiceInterfaceType.Namespace}.{ctx.Definition.ServiceInterfaceType.Name}Client", TypeAttributes.Public | TypeAttributes.Sealed, constructedBaseClientType, new[] { ctx.Definition.ServiceInterfaceType }); - // Set `IgnoreAttribute` to the generated client type. Hides generated-types from building MagicOnion service definitions. - ctx.ServiceClientType.SetCustomAttribute(new CustomAttributeBuilder(typeof(IgnoreAttribute).GetConstructor(Type.EmptyTypes)!, Array.Empty())); - { - // class ClientCore { ... } - EmitClientCore(ctx); - // private readonly ClientCore core; ... - EmitFields(ctx); - // public {ServiceName}Client(MagicOnionClientOptions options, IMagicOnionSerializerProvider serializerProvider) { ... } - // private {ServiceName}Client(MagicOnionClientOptions options, ClientCore clientCore) { ... } - EmitConstructor(ctx); - // protected override ClientBase<{ServiceName}> Clone(MagicOnionClientOptions options) => new {ServiceName}Client(options, core); - EmitClone(ctx, constructedBaseClientType); - // public {MethodType}Result MethodName(TArg1 arg1, TArg2 arg2, ...) => this.core.MethodName.Invoke{MethodType}(this, "ServiceName/MethodName", new DynamicArgumentTuple(arg1, arg2, ...)); ... - EmitServiceMethods(ctx); - } - // } + // class ClientCore { ... } + EmitClientCore(ctx); + // private readonly ClientCore core; ... + EmitFields(ctx); + // public {ServiceName}Client(MagicOnionClientOptions options, IMagicOnionSerializerProvider serializerProvider) { ... } + // private {ServiceName}Client(MagicOnionClientOptions options, ClientCore clientCore) { ... } + EmitConstructor(ctx); + // protected override ClientBase<{ServiceName}> Clone(MagicOnionClientOptions options) => new {ServiceName}Client(options, core); + EmitClone(ctx, constructedBaseClientType); + // public {MethodType}Result MethodName(TArg1 arg1, TArg2 arg2, ...) => this.core.MethodName.Invoke{MethodType}(this, "ServiceName/MethodName", new DynamicArgumentTuple(arg1, arg2, ...)); ... + EmitServiceMethods(ctx); } + // } + } - static void EmitClone(ServiceClientBuildContext ctx, Type constructedBaseClientType) + static void EmitClone(ServiceClientBuildContext ctx, Type constructedBaseClientType) + { + // protected override MagicOnionClientBase<{ServiceName}> Clone(MagicOnionClientOptions options) => new {ServiceName}Client(options, core); + var cloneMethodBuilder = ctx.ServiceClientType.DefineMethod("Clone", MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.Final, constructedBaseClientType, new[] { typeof(MagicOnionClientOptions) }); { - // protected override MagicOnionClientBase<{ServiceName}> Clone(MagicOnionClientOptions options) => new {ServiceName}Client(options, core); - var cloneMethodBuilder = ctx.ServiceClientType.DefineMethod("Clone", MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.Final, constructedBaseClientType, new[] { typeof(MagicOnionClientOptions) }); - { - var il = cloneMethodBuilder.GetILGenerator(); - il.Emit(OpCodes.Ldarg_1); // options - il.Emit(OpCodes.Ldarg_0); // this. - il.Emit(OpCodes.Ldfld, ctx.FieldCore); // core - il.Emit(OpCodes.Newobj, ctx.ServiceClientConstructorForClone); // new {ServiceName}Client(options, core); - il.Emit(OpCodes.Ret); - } + var il = cloneMethodBuilder.GetILGenerator(); + il.Emit(OpCodes.Ldarg_1); // options + il.Emit(OpCodes.Ldarg_0); // this. + il.Emit(OpCodes.Ldfld, ctx.FieldCore); // core + il.Emit(OpCodes.Newobj, ctx.ServiceClientConstructorForClone); // new {ServiceName}Client(options, core); + il.Emit(OpCodes.Ret); } + } - static void EmitConstructor(ServiceClientBuildContext ctx) + static void EmitConstructor(ServiceClientBuildContext ctx) + { + var baseCtor = ctx.ServiceClientType.BaseType!.GetConstructor( + BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, + null, + CallingConventions.Standard, + new[] { typeof(MagicOnionClientOptions) }, + Array.Empty() + )!; + // public {ServiceName}Client(MagicOnionClientOptions options, IMagicOnionSerializerProvider serializerProvider) { + ctx.ServiceClientConstructor = ctx.ServiceClientType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, KnownTypes.ClientConstructorParameters); { - var baseCtor = ctx.ServiceClientType.BaseType!.GetConstructor( - BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, - null, - CallingConventions.Standard, - new[] { typeof(MagicOnionClientOptions) }, - Array.Empty() - )!; - // public {ServiceName}Client(MagicOnionClientOptions options, IMagicOnionSerializerProvider serializerProvider) { - ctx.ServiceClientConstructor = ctx.ServiceClientType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, KnownTypes.ClientConstructorParameters); - { - var il = ctx.ServiceClientConstructor.GetILGenerator(); - // base(options); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Call, baseCtor); - // this.core = new ClientCore(serializerProvider); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_2); - il.Emit(OpCodes.Newobj, ctx.ClientCoreConstructor); - il.Emit(OpCodes.Stfld, ctx.FieldCore); - il.Emit(OpCodes.Ret); - } - // } - - // private {ServiceName}Client(MagicOnionClientOptions options, ClientCore clientCore) { - ctx.ServiceClientConstructorForClone = ctx.ServiceClientType.DefineConstructor(MethodAttributes.Private, CallingConventions.Standard, new [] { typeof(MagicOnionClientOptions), ctx.ClientCoreType }); - { - var il = ctx.ServiceClientConstructorForClone.GetILGenerator(); - // base(options); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Call, baseCtor); - // this.core = core; - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_2); - il.Emit(OpCodes.Stfld, ctx.FieldCore); - il.Emit(OpCodes.Ret); - } - // } + var il = ctx.ServiceClientConstructor.GetILGenerator(); + // base(options); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Call, baseCtor); + // this.core = new ClientCore(serializerProvider); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Newobj, ctx.ClientCoreConstructor); + il.Emit(OpCodes.Stfld, ctx.FieldCore); + il.Emit(OpCodes.Ret); } + // } - static void EmitFields(ServiceClientBuildContext ctx) + // private {ServiceName}Client(MagicOnionClientOptions options, ClientCore clientCore) { + ctx.ServiceClientConstructorForClone = ctx.ServiceClientType.DefineConstructor(MethodAttributes.Private, CallingConventions.Standard, new [] { typeof(MagicOnionClientOptions), ctx.ClientCoreType }); { - // private readonly ClientCore core; - ctx.FieldCore = ctx.ServiceClientType.DefineField("core", ctx.ClientCoreType, FieldAttributes.Private); + var il = ctx.ServiceClientConstructorForClone.GetILGenerator(); + // base(options); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Call, baseCtor); + // this.core = core; + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Stfld, ctx.FieldCore); + il.Emit(OpCodes.Ret); } + // } + } + + static void EmitFields(ServiceClientBuildContext ctx) + { + // private readonly ClientCore core; + ctx.FieldCore = ctx.ServiceClientType.DefineField("core", ctx.ClientCoreType, FieldAttributes.Private); + } - static void EmitServiceMethods(ServiceClientBuildContext ctx) + static void EmitServiceMethods(ServiceClientBuildContext ctx) + { + // Implements + // public UnaryResult MethodName(TArg1 arg1, TArg2 arg2, ...) + // => this.core.MethodName.InvokeUnary(this, "ServiceName/MethodName", new DynamicArgumentTuple(arg1, arg2, ...)); + // public UnaryResult MethodName(TRequest request) + // => this.core.MethodName.InvokeUnary(this, "ServiceName/MethodName", request); + // public UnaryResult MethodName() + // => this.core.MethodName.InvokeUnary(this, "ServiceName/MethodName", Nil.Default); + // public UnaryResult MethodName() + // => this.core.MethodName.InvokeUnaryNonGeneric(this, "ServiceName/MethodName", Nil.Default); + // public Task> MethodName(TArg1 arg1, TArg2 arg2, ...) + // => this.core.MethodName.InvokeServerStreaming(this, "ServiceName/MethodName", new DynamicArgumentTuple(arg1, arg2, ...)); + // public Task> MethodName() + // => this.core.MethodName.InvokeClientStreaming(this, "ServiceName/MethodName"); + // public Task> MethodName() + // => this.core.MethodName.InvokeDuplexStreaming(this, "ServiceName/MethodName"); + foreach (var method in ctx.Definition.Methods) { - // Implements - // public UnaryResult MethodName(TArg1 arg1, TArg2 arg2, ...) - // => this.core.MethodName.InvokeUnary(this, "ServiceName/MethodName", new DynamicArgumentTuple(arg1, arg2, ...)); - // public UnaryResult MethodName(TRequest request) - // => this.core.MethodName.InvokeUnary(this, "ServiceName/MethodName", request); - // public UnaryResult MethodName() - // => this.core.MethodName.InvokeUnary(this, "ServiceName/MethodName", Nil.Default); - // public UnaryResult MethodName() - // => this.core.MethodName.InvokeUnaryNonGeneric(this, "ServiceName/MethodName", Nil.Default); - // public Task> MethodName(TArg1 arg1, TArg2 arg2, ...) - // => this.core.MethodName.InvokeServerStreaming(this, "ServiceName/MethodName", new DynamicArgumentTuple(arg1, arg2, ...)); - // public Task> MethodName() - // => this.core.MethodName.InvokeClientStreaming(this, "ServiceName/MethodName"); - // public Task> MethodName() - // => this.core.MethodName.InvokeDuplexStreaming(this, "ServiceName/MethodName"); - foreach (var method in ctx.Definition.Methods) - { - var hasNonGenericUnaryResult = method.MethodReturnType == typeof(UnaryResult); - var methodInvokerInvokeMethod = ctx.FieldAndMethodInvokerTypeByMethod[method.MethodName].MethodInvokerType.GetMethod($"Invoke{method.MethodType}{(hasNonGenericUnaryResult ? "NonGeneric" : "")}")!; - var methodBuilder = ctx.ServiceClientType.DefineMethod(method.MethodName, MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, methodInvokerInvokeMethod.ReturnType, method.ParameterTypes.ToArray()); - var il = methodBuilder.GetILGenerator(); + var hasNonGenericUnaryResult = method.MethodReturnType == typeof(UnaryResult); + var methodInvokerInvokeMethod = ctx.FieldAndMethodInvokerTypeByMethod[method.MethodName].MethodInvokerType.GetMethod($"Invoke{method.MethodType}{(hasNonGenericUnaryResult ? "NonGeneric" : "")}")!; + var methodBuilder = ctx.ServiceClientType.DefineMethod(method.MethodName, MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, methodInvokerInvokeMethod.ReturnType, method.ParameterTypes.ToArray()); + var il = methodBuilder.GetILGenerator(); - // return this.core.{Method}( - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, ctx.FieldCore); - il.Emit(OpCodes.Ldfld, ctx.FieldAndMethodInvokerTypeByMethod[method.MethodName].Field); - // this, - il.Emit(OpCodes.Ldarg_0); - // method.Path, - il.Emit(OpCodes.Ldstr, method.Path); + // return this.core.{Method}( + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, ctx.FieldCore); + il.Emit(OpCodes.Ldfld, ctx.FieldAndMethodInvokerTypeByMethod[method.MethodName].Field); + // this, + il.Emit(OpCodes.Ldarg_0); + // method.Path, + il.Emit(OpCodes.Ldstr, method.Path); - if (method.MethodType == MethodType.Unary || method.MethodType == MethodType.ServerStreaming) + if (method.MethodType == MethodType.Unary || method.MethodType == MethodType.ServerStreaming) + { + if (method.ParameterTypes.Count > 0) { - if (method.ParameterTypes.Count > 0) + if (method.ParameterTypes.Count == 1) { - if (method.ParameterTypes.Count == 1) - { - // arg1 - il.Emit(OpCodes.Ldarg_1); - } - else + // arg1 + il.Emit(OpCodes.Ldarg_1); + } + else + { + // new DynamicArgumentTuple(arg1, arg2, ...) + for (var i = 0; i < method.ParameterTypes.Count; i++) { - // new DynamicArgumentTuple(arg1, arg2, ...) - for (var i = 0; i < method.ParameterTypes.Count; i++) + switch (i) { - switch (i) - { - case 0: - il.Emit(OpCodes.Ldarg_1); - break; - case 1: - il.Emit(OpCodes.Ldarg_2); - break; - case 2: - il.Emit(OpCodes.Ldarg_3); - break; - default: - il.Emit(OpCodes.Ldarg, i + 1); - break; - } + case 0: + il.Emit(OpCodes.Ldarg_1); + break; + case 1: + il.Emit(OpCodes.Ldarg_2); + break; + case 2: + il.Emit(OpCodes.Ldarg_3); + break; + default: + il.Emit(OpCodes.Ldarg, i + 1); + break; } - il.Emit(OpCodes.Newobj, method.RequestType.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, method.ParameterTypes.ToArray(), Array.Empty())!); } - } - else if (method.ParameterTypes.Count == 0) - { - // Nil.Default - il.Emit(OpCodes.Ldsfld, typeof(Nil).GetField("Default", BindingFlags.Public | BindingFlags.Static)!); + il.Emit(OpCodes.Newobj, method.RequestType.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, method.ParameterTypes.ToArray(), Array.Empty())!); } } - else + else if (method.ParameterTypes.Count == 0) { - // Invoker for ClientStreaming, DuplexStreaming has no request parameter. + // Nil.Default + il.Emit(OpCodes.Ldsfld, typeof(Nil).GetField("Default", BindingFlags.Public | BindingFlags.Static)!); } - - // ); - il.Emit(OpCodes.Callvirt, methodInvokerInvokeMethod); - il.Emit(OpCodes.Ret); } + else + { + // Invoker for ClientStreaming, DuplexStreaming has no request parameter. + } + + // ); + il.Emit(OpCodes.Callvirt, methodInvokerInvokeMethod); + il.Emit(OpCodes.Ret); } + } - static void EmitClientCore(ServiceClientBuildContext ctx) + static void EmitClientCore(ServiceClientBuildContext ctx) + { + /* + * class ClientCore + * { + * // UnaryResult HelloAsync(string name, int age); + * public UnaryMethodRawInvoker, string> HelloAsync; + * + * public ClientCore(IMagicOnionSerializerProvider serializerProvider) + * { + * this.HelloAsync = UnaryMethodRawInvoker.Create_ValueType_RefType, string>("IGreeterService", "HelloAsync", serializerProvider); + * } + * } + */ + + // class ClientCore { + ctx.ClientCoreType = ctx.ServiceClientType.DefineNestedType("ClientCore"); { - /* - * class ClientCore - * { - * // UnaryResult HelloAsync(string name, int age); - * public UnaryMethodRawInvoker, string> HelloAsync; - * - * public ClientCore(IMagicOnionSerializerProvider serializerProvider) - * { - * this.HelloAsync = UnaryMethodRawInvoker.Create_ValueType_RefType, string>("IGreeterService", "HelloAsync", serializerProvider); - * } - * } - */ + // public RawMethodInvoker MethodName; + foreach (var method in ctx.Definition.Methods) + { + var methodInvokerType = typeof(RawMethodInvoker<,>).MakeGenericType(method.RequestType, method.ResponseType); + var field = ctx.ClientCoreType.DefineField(method.MethodName, methodInvokerType, FieldAttributes.Public); + ctx.FieldAndMethodInvokerTypeByMethod[method.MethodName] = (field, methodInvokerType); + } - // class ClientCore { - ctx.ClientCoreType = ctx.ServiceClientType.DefineNestedType("ClientCore"); + // public ClientCore(IMagicOnionSerializerProvider serializerProvider) { + ctx.ClientCoreConstructor = ctx.ClientCoreType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, KnownTypes.ClientCoreConstructorParameters); { - // public RawMethodInvoker MethodName; - foreach (var method in ctx.Definition.Methods) - { - var methodInvokerType = typeof(RawMethodInvoker<,>).MakeGenericType(method.RequestType, method.ResponseType); - var field = ctx.ClientCoreType.DefineField(method.MethodName, methodInvokerType, FieldAttributes.Public); - ctx.FieldAndMethodInvokerTypeByMethod[method.MethodName] = (field, methodInvokerType); - } + var il = ctx.ClientCoreConstructor.GetILGenerator(); - // public ClientCore(IMagicOnionSerializerProvider serializerProvider) { - ctx.ClientCoreConstructor = ctx.ClientCoreType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, KnownTypes.ClientCoreConstructorParameters); + // MethodName = RawMethodInvoker.Create_XXXType_XXXType(MethodType, ServiceName, MethodName, serializerProvider); + foreach (var method in ctx.Definition.Methods) { - var il = ctx.ClientCoreConstructor.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); - // MethodName = RawMethodInvoker.Create_XXXType_XXXType(MethodType, ServiceName, MethodName, serializerProvider); - foreach (var method in ctx.Definition.Methods) - { - il.Emit(OpCodes.Ldarg_0); - - var (field, _) = ctx.FieldAndMethodInvokerTypeByMethod[method.MethodName]; - var methodInvokerType = RawMethodInvokerTypes.GetMethodRawInvokerCreateMethod(method.RequestType, method.ResponseType); - // RawMethodInvoker.Create_XXXType_XXXType( - il.Emit(OpCodes.Ldc_I4, (int)method.MethodType); // methodType, - il.Emit(OpCodes.Ldstr, method.ServiceName); // serviceName, - il.Emit(OpCodes.Ldstr, method.MethodName); // methodName, - il.Emit(OpCodes.Ldarg_1); // serializerProvider - il.Emit(OpCodes.Call, methodInvokerType); - // ); + var (field, _) = ctx.FieldAndMethodInvokerTypeByMethod[method.MethodName]; + var methodInvokerType = RawMethodInvokerTypes.GetMethodRawInvokerCreateMethod(method.RequestType, method.ResponseType); + // RawMethodInvoker.Create_XXXType_XXXType( + il.Emit(OpCodes.Ldc_I4, (int)method.MethodType); // methodType, + il.Emit(OpCodes.Ldstr, method.ServiceName); // serviceName, + il.Emit(OpCodes.Ldstr, method.MethodName); // methodName, + il.Emit(OpCodes.Ldarg_1); // serializerProvider + il.Emit(OpCodes.Call, methodInvokerType); + // ); - // = ; - il.Emit(OpCodes.Stfld, field); - } - il.Emit(OpCodes.Ret); + // = ; + il.Emit(OpCodes.Stfld, field); } - // } + il.Emit(OpCodes.Ret); } // } - _ = ctx.ClientCoreType.CreateTypeInfo(); // Build } + // } + _ = ctx.ClientCoreType.CreateTypeInfo(); // Build } } diff --git a/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs b/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs index 0b3b64d81..7b67647ad 100644 --- a/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs +++ b/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs @@ -1,40 +1,39 @@ using System.Diagnostics.CodeAnalysis; -namespace MagicOnion.Client.DynamicClient +namespace MagicOnion.Client.DynamicClient; + +public class DynamicNotSupportedMagicOnionClientFactoryProvider : IMagicOnionClientFactoryProvider { - public class DynamicNotSupportedMagicOnionClientFactoryProvider : IMagicOnionClientFactoryProvider + public static IMagicOnionClientFactoryProvider Instance { get; } = new DynamicNotSupportedMagicOnionClientFactoryProvider(); + + DynamicNotSupportedMagicOnionClientFactoryProvider() { } + + public bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDelegate? factory) where T : IService { - public static IMagicOnionClientFactoryProvider Instance { get; } = new DynamicNotSupportedMagicOnionClientFactoryProvider(); + throw new InvalidOperationException($"Unable to find a client factory of type '{typeof(T)}'. If the application is running on IL2CPP or AOT, dynamic code generation is not supported. Please use the code generator (moc)."); + } +} + +/// +/// Provides to get a MagicOnionClient factory of the specified service type. The provider is backed by DynamicMagicOnionClientBuilder. +/// +[RequiresUnreferencedCode(nameof(DynamicMagicOnionClientFactoryProvider) + " is incompatible with trimming and Native AOT.")] +public class DynamicMagicOnionClientFactoryProvider : IMagicOnionClientFactoryProvider +{ + public static IMagicOnionClientFactoryProvider Instance { get; } = new DynamicMagicOnionClientFactoryProvider(); - DynamicNotSupportedMagicOnionClientFactoryProvider() { } + DynamicMagicOnionClientFactoryProvider() { } - public bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDelegate? factory) where T : IService - { - throw new InvalidOperationException($"Unable to find a client factory of type '{typeof(T)}'. If the application is running on IL2CPP or AOT, dynamic code generation is not supported. Please use the code generator (moc)."); - } + public bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDelegate? factory) where T : IService + { + factory = Cache.Factory; + return true; } - /// - /// Provides to get a MagicOnionClient factory of the specified service type. The provider is backed by DynamicMagicOnionClientBuilder. - /// - [RequiresUnreferencedCode(nameof(DynamicMagicOnionClientFactoryProvider) + " is incompatible with trimming and Native AOT.")] - public class DynamicMagicOnionClientFactoryProvider : IMagicOnionClientFactoryProvider + [RequiresUnreferencedCode(nameof(DynamicMagicOnionClientFactoryProvider) + "." + nameof(Cache) + " is incompatible with trimming and Native AOT.")] + static class Cache where T : IService { - public static IMagicOnionClientFactoryProvider Instance { get; } = new DynamicMagicOnionClientFactoryProvider(); - - DynamicMagicOnionClientFactoryProvider() { } - - public bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDelegate? factory) where T : IService - { - factory = Cache.Factory; - return true; - } - - [RequiresUnreferencedCode(nameof(DynamicMagicOnionClientFactoryProvider) + "." + nameof(Cache) + " is incompatible with trimming and Native AOT.")] - static class Cache where T : IService - { - public static readonly MagicOnionClientFactoryDelegate Factory - = (clientOptions, serializerProvider) => (T)Activator.CreateInstance(DynamicClientBuilder.ClientType, clientOptions, serializerProvider)!; - } + public static readonly MagicOnionClientFactoryDelegate Factory + = (clientOptions, serializerProvider) => (T)Activator.CreateInstance(DynamicClientBuilder.ClientType, clientOptions, serializerProvider)!; } } diff --git a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs index 7646f8562..7803d46e2 100644 --- a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs +++ b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs @@ -7,25 +7,25 @@ using System.Reflection; using System.Reflection.Emit; -namespace MagicOnion.Client.DynamicClient -{ - [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientAssemblyHolder) + " is incompatible with trimming and Native AOT.")] +namespace MagicOnion.Client.DynamicClient; + +[RequiresUnreferencedCode(nameof(DynamicStreamingHubClientAssemblyHolder) + " is incompatible with trimming and Native AOT.")] #if ENABLE_SAVE_ASSEMBLY public #else - internal +internal #endif - static class DynamicStreamingHubClientAssemblyHolder - { - public const string ModuleName = "MagicOnion.Client.StreamingHubClient"; + static class DynamicStreamingHubClientAssemblyHolder +{ + public const string ModuleName = "MagicOnion.Client.StreamingHubClient"; - readonly static DynamicAssembly assembly; - internal static DynamicAssembly Assembly { get { return assembly; } } + readonly static DynamicAssembly assembly; + internal static DynamicAssembly Assembly { get { return assembly; } } - static DynamicStreamingHubClientAssemblyHolder() - { - assembly = new DynamicAssembly(ModuleName); - } + static DynamicStreamingHubClientAssemblyHolder() + { + assembly = new DynamicAssembly(ModuleName); + } #if ENABLE_SAVE_ASSEMBLY @@ -35,747 +35,746 @@ public static AssemblyBuilder Save() } #endif - } +} - [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientBuilder) + " is incompatible with trimming and Native AOT.")] +[RequiresUnreferencedCode(nameof(DynamicStreamingHubClientBuilder) + " is incompatible with trimming and Native AOT.")] #if ENABLE_SAVE_ASSEMBLY public #else - internal +internal #endif - static class DynamicStreamingHubClientBuilder - where TStreamingHub : IStreamingHub + static class DynamicStreamingHubClientBuilder + where TStreamingHub : IStreamingHub +{ + public static readonly Type ClientType; + // static readonly Type ClientFireAndForgetType; + + static readonly ConstructorInfo notSupportedException = typeof(NotSupportedException).GetConstructor(Type.EmptyTypes)!; + + static DynamicStreamingHubClientBuilder() { - public static readonly Type ClientType; - // static readonly Type ClientFireAndForgetType; + var t = typeof(TStreamingHub); + var ti = t.GetTypeInfo(); + if (!ti.IsInterface) throw new Exception("Client Proxy only allows interface. Type:" + ti.Name); + var asm = DynamicStreamingHubClientAssemblyHolder.Assembly; + var methodDefinitions = SearchDefinitions(t); - static readonly ConstructorInfo notSupportedException = typeof(NotSupportedException).GetConstructor(Type.EmptyTypes)!; + var parentType = typeof(StreamingHubClientBase<,>).MakeGenericType(typeof(TStreamingHub), typeof(TReceiver)); + var typeBuilder = asm.DefineType($"{DynamicClientAssemblyHolder.ModuleName}.{ti.FullName}StreamingHubClient_{Guid.NewGuid().ToString()}", TypeAttributes.Public, parentType, new Type[] { t }); + + VerifyMethodDefinitions(methodDefinitions); - static DynamicStreamingHubClientBuilder() { - var t = typeof(TStreamingHub); - var ti = t.GetTypeInfo(); - if (!ti.IsInterface) throw new Exception("Client Proxy only allows interface. Type:" + ti.Name); - var asm = DynamicStreamingHubClientAssemblyHolder.Assembly; - var methodDefinitions = SearchDefinitions(t); + // Create FireAndForgetType first as nested type. + var typeBuilderEx = typeBuilder.DefineNestedType($"FireAndForgetClient", TypeAttributes.NestedPrivate, typeof(object), new Type[] { t }); + var tuple = DefineFireAndForgetConstructor(typeBuilderEx, typeBuilder); + var fireAndForgetClientCtor = tuple.Item1; + var fireAndForgetField = tuple.Item2; - var parentType = typeof(StreamingHubClientBase<,>).MakeGenericType(typeof(TStreamingHub), typeof(TReceiver)); - var typeBuilder = asm.DefineType($"{DynamicClientAssemblyHolder.ModuleName}.{ti.FullName}StreamingHubClient_{Guid.NewGuid().ToString()}", TypeAttributes.Public, parentType, new Type[] { t }); + DefineMethodsFireAndForget(typeBuilderEx, t, fireAndForgetField, typeBuilder, methodDefinitions); + typeBuilderEx.CreateTypeInfo(); // ok to create nested type. - VerifyMethodDefinitions(methodDefinitions); + var clientField = DefineConstructor(typeBuilder, t, typeof(TReceiver), fireAndForgetClientCtor); + DefineMethods(typeBuilder, t, typeof(TReceiver), clientField, methodDefinitions); + } + ClientType = typeBuilder.CreateTypeInfo()!.AsType(); + } + + static MethodDefinition[] SearchDefinitions(Type interfaceType) + { + return interfaceType + .GetInterfaces() + .Concat(new[] { interfaceType }) + .SelectMany(x => x.GetMethods()) + .Where(x => { - // Create FireAndForgetType first as nested type. - var typeBuilderEx = typeBuilder.DefineNestedType($"FireAndForgetClient", TypeAttributes.NestedPrivate, typeof(object), new Type[] { t }); - var tuple = DefineFireAndForgetConstructor(typeBuilderEx, typeBuilder); - var fireAndForgetClientCtor = tuple.Item1; - var fireAndForgetField = tuple.Item2; + var methodInfo = x; + if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_"))) return false; + if (methodInfo.GetCustomAttribute(false) != null) return false; // ignore + + var methodName = methodInfo.Name; + if (methodName == "Equals" + || methodName == "GetHashCode" + || methodName == "GetType" + || methodName == "ToString" + || methodName == "DisposeAsync" + || methodName == "WaitForDisconnect" + || methodName == "FireAndForget" + ) + { + return false; + } + return true; + }) + .Where(x => !x.IsSpecialName) + .Select(x => new MethodDefinition(interfaceType, x, default, default)) + .ToArray(); + } - DefineMethodsFireAndForget(typeBuilderEx, t, fireAndForgetField, typeBuilder, methodDefinitions); - typeBuilderEx.CreateTypeInfo(); // ok to create nested type. + static void VerifyMethodDefinitions(MethodDefinition[] definitions) + { + var map = new Dictionary(definitions.Length); + foreach (var item in definitions) + { + var methodId = item.MethodInfo.GetCustomAttribute()?.MethodId ?? FNV1A32.GetHashCode(item.MethodInfo.Name); + if (map.ContainsKey(methodId)) + { + throw new Exception($"TStreamingHub does not allows duplicate methodId(hash code). Please change name or use MethodIdAttribute. {map[methodId].MethodInfo.Name} and {item.MethodInfo.Name}"); + } + map.Add(methodId, item); + + var returnTypeNonGenericOrOpenGeneric = item.MethodInfo.ReturnType.IsGenericType ? item.MethodInfo.ReturnType.GetGenericTypeDefinition() : item.MethodInfo.ReturnType; - var clientField = DefineConstructor(typeBuilder, t, typeof(TReceiver), fireAndForgetClientCtor); - DefineMethods(typeBuilder, t, typeof(TReceiver), clientField, methodDefinitions); + if (returnTypeNonGenericOrOpenGeneric != typeof(ValueTask) && + returnTypeNonGenericOrOpenGeneric != typeof(Task) && + returnTypeNonGenericOrOpenGeneric != typeof(ValueTask<>) && + returnTypeNonGenericOrOpenGeneric != typeof(Task<>) && + returnTypeNonGenericOrOpenGeneric != typeof(void)) + { + throw new Exception($"Invalid definition, TStreamingHub's return type must only be `void`, `Task`, `Task`, `ValueTask` or `ValueTask`. {item.MethodInfo.Name}."); } - ClientType = typeBuilder.CreateTypeInfo()!.AsType(); + item.MethodId = methodId; + if (item.RequestType == null) + { + item.RequestType = MagicOnionMarshallers.CreateRequestType(item.MethodInfo.GetParameters()); + } } + } - static MethodDefinition[] SearchDefinitions(Type interfaceType) + static FieldInfo DefineConstructor(TypeBuilder typeBuilder, Type interfaceType, Type receiverType, ConstructorInfo fireAndForgetClientCtor) + { + // .ctor(TReceiver receiver, CallInvoker callInvoker, StreamingHubClientOptions options) : base("InterfaceName", receiver, callInvoker, options) { - return interfaceType - .GetInterfaces() - .Concat(new[] { interfaceType }) - .SelectMany(x => x.GetMethods()) - .Where(x => - { - var methodInfo = x; - if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_"))) return false; - if (methodInfo.GetCustomAttribute(false) != null) return false; // ignore - - var methodName = methodInfo.Name; - if (methodName == "Equals" - || methodName == "GetHashCode" - || methodName == "GetType" - || methodName == "ToString" - || methodName == "DisposeAsync" - || methodName == "WaitForDisconnect" - || methodName == "FireAndForget" - ) - { - return false; - } - return true; - }) - .Where(x => !x.IsSpecialName) - .Select(x => new MethodDefinition(interfaceType, x, default, default)) - .ToArray(); + var argTypes = new[] { receiverType, typeof(CallInvoker), typeof(StreamingHubClientOptions) }; + var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, argTypes); + var il = ctor.GetILGenerator(); + + // base("InterfaceName", receiver, callInvoker, options); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldstr, interfaceType.Name); + il.Emit(OpCodes.Ldarg_1); // receiver + il.Emit(OpCodes.Ldarg_2); // callInvoker + il.Emit(OpCodes.Ldarg_3); // options + il.Emit(OpCodes.Call, typeBuilder.BaseType! + .GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).First()); + + // { this.fireAndForgetClient = new FireAndForgetClient(this); } + var clientField = typeBuilder.DefineField("fireAndForgetClient", fireAndForgetClientCtor.DeclaringType!, FieldAttributes.Private); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Newobj, fireAndForgetClientCtor); + il.Emit(OpCodes.Stfld, clientField); + + il.Emit(OpCodes.Ret); + + return clientField; } + } - static void VerifyMethodDefinitions(MethodDefinition[] definitions) + static Tuple DefineFireAndForgetConstructor(TypeBuilder typeBuilder, Type parentClientType) + { + // .ctor(Parent client) { this.client = client } { - var map = new Dictionary(definitions.Length); - foreach (var item in definitions) - { - var methodId = item.MethodInfo.GetCustomAttribute()?.MethodId ?? FNV1A32.GetHashCode(item.MethodInfo.Name); - if (map.ContainsKey(methodId)) - { - throw new Exception($"TStreamingHub does not allows duplicate methodId(hash code). Please change name or use MethodIdAttribute. {map[methodId].MethodInfo.Name} and {item.MethodInfo.Name}"); - } - map.Add(methodId, item); + var argTypes = new[] { parentClientType }; + var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, argTypes); + var clientField = typeBuilder.DefineField("client", parentClientType, FieldAttributes.Private); + var il = ctor.GetILGenerator(); - var returnTypeNonGenericOrOpenGeneric = item.MethodInfo.ReturnType.IsGenericType ? item.MethodInfo.ReturnType.GetGenericTypeDefinition() : item.MethodInfo.ReturnType; + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, typeof(object).GetConstructors().First()); - if (returnTypeNonGenericOrOpenGeneric != typeof(ValueTask) && - returnTypeNonGenericOrOpenGeneric != typeof(Task) && - returnTypeNonGenericOrOpenGeneric != typeof(ValueTask<>) && - returnTypeNonGenericOrOpenGeneric != typeof(Task<>) && - returnTypeNonGenericOrOpenGeneric != typeof(void)) - { - throw new Exception($"Invalid definition, TStreamingHub's return type must only be `void`, `Task`, `Task`, `ValueTask` or `ValueTask`. {item.MethodInfo.Name}."); - } + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Stfld, clientField); - item.MethodId = methodId; - if (item.RequestType == null) - { - item.RequestType = MagicOnionMarshallers.CreateRequestType(item.MethodInfo.GetParameters()); - } - } + il.Emit(OpCodes.Ret); + + return Tuple.Create(ctor, clientField); } + } + + static void DefineMethods(TypeBuilder typeBuilder, Type interfaceType, Type receiverType, FieldInfo clientField, MethodDefinition[] definitions) + { + var baseType = typeof(StreamingHubClientBase<,>).MakeGenericType(interfaceType, receiverType); + var receiverField = baseType.GetField("receiver", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; - static FieldInfo DefineConstructor(TypeBuilder typeBuilder, Type interfaceType, Type receiverType, ConstructorInfo fireAndForgetClientCtor) { - // .ctor(TReceiver receiver, CallInvoker callInvoker, StreamingHubClientOptions options) : base("InterfaceName", receiver, callInvoker, options) + // Task DisposeAsync(); { - var argTypes = new[] { receiverType, typeof(CallInvoker), typeof(StreamingHubClientOptions) }; - var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, argTypes); - var il = ctor.GetILGenerator(); + var method = typeBuilder.DefineMethod("DisposeAsync", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + typeof(Task), Type.EmptyTypes); + var il = method.GetILGenerator(); - // base("InterfaceName", receiver, callInvoker, options); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldstr, interfaceType.Name); - il.Emit(OpCodes.Ldarg_1); // receiver - il.Emit(OpCodes.Ldarg_2); // callInvoker - il.Emit(OpCodes.Ldarg_3); // options - il.Emit(OpCodes.Call, typeBuilder.BaseType! - .GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).First()); - - // { this.fireAndForgetClient = new FireAndForgetClient(this); } - var clientField = typeBuilder.DefineField("fireAndForgetClient", fireAndForgetClientCtor.DeclaringType!, FieldAttributes.Private); - il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Newobj, fireAndForgetClientCtor); - il.Emit(OpCodes.Stfld, clientField); - + il.Emit(OpCodes.Call, baseType.GetMethod("DisposeAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!); il.Emit(OpCodes.Ret); - - return clientField; } - } - - static Tuple DefineFireAndForgetConstructor(TypeBuilder typeBuilder, Type parentClientType) - { - // .ctor(Parent client) { this.client = client } + // Task WaitForDisconnect(); { - var argTypes = new[] { parentClientType }; - var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, argTypes); - var clientField = typeBuilder.DefineField("client", parentClientType, FieldAttributes.Private); - var il = ctor.GetILGenerator(); + var method = typeBuilder.DefineMethod("WaitForDisconnect", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + typeof(Task), Type.EmptyTypes); + var il = method.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, typeof(object).GetConstructors().First()); + il.Emit(OpCodes.Call, baseType.GetMethod("WaitForDisconnect", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!); + il.Emit(OpCodes.Ret); + } + // TSelf FireAndForget(); + { + var method = typeBuilder.DefineMethod("FireAndForget", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + interfaceType, Type.EmptyTypes); + var il = method.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Stfld, clientField); - + il.Emit(OpCodes.Ldfld, clientField); il.Emit(OpCodes.Ret); - - return Tuple.Create(ctor, clientField); } } - static void DefineMethods(TypeBuilder typeBuilder, Type interfaceType, Type receiverType, FieldInfo clientField, MethodDefinition[] definitions) + // receiver types borrow from DynamicBroadcastBuilder { - var baseType = typeof(StreamingHubClientBase<,>).MakeGenericType(interfaceType, receiverType); - var receiverField = baseType.GetField("receiver", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; - + // protected abstract void OnResponseEvent(int methodId, object taskSource, ReadOnlyMemory data); { - // Task DisposeAsync(); - { - var method = typeBuilder.DefineMethod("DisposeAsync", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - typeof(Task), Type.EmptyTypes); - var il = method.GetILGenerator(); + var method = typeBuilder.DefineMethod("OnResponseEvent", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + null, new[] { typeof(int), typeof(object), typeof(ReadOnlyMemory) }); + var il = method.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, baseType.GetMethod("DisposeAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!); - il.Emit(OpCodes.Ret); - } - // Task WaitForDisconnect(); - { - var method = typeBuilder.DefineMethod("WaitForDisconnect", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - typeof(Task), Type.EmptyTypes); - var il = method.GetILGenerator(); + var labels = definitions + .Where(x => x.MethodInfo.ReturnType != typeof(void)) // If the return type if `void`, we always need to treat as fire-and-forget. + .Select(x => new { def = x, label = il.DefineLabel() }) + .ToArray(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Call, baseType.GetMethod("WaitForDisconnect", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!); - il.Emit(OpCodes.Ret); - } - // TSelf FireAndForget(); + foreach (var item in labels) { - var method = typeBuilder.DefineMethod("FireAndForget", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - interfaceType, Type.EmptyTypes); - var il = method.GetILGenerator(); - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, clientField); - il.Emit(OpCodes.Ret); + // if( == ) goto ... + il.Emit(OpCodes.Ldarg_1); + il.EmitLdc_I4(item.def.MethodId); + il.Emit(OpCodes.Beq, item.label); } - } + // else + il.Emit(OpCodes.Ret); - // receiver types borrow from DynamicBroadcastBuilder - { - // protected abstract void OnResponseEvent(int methodId, object taskSource, ReadOnlyMemory data); + foreach (var item in labels) { - var method = typeBuilder.DefineMethod("OnResponseEvent", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - null, new[] { typeof(int), typeof(object), typeof(ReadOnlyMemory) }); - var il = method.GetILGenerator(); + // SetResultForResponse(taskSource, data); + Type responseType; - var labels = definitions - .Where(x => x.MethodInfo.ReturnType != typeof(void)) // If the return type if `void`, we always need to treat as fire-and-forget. - .Select(x => new { def = x, label = il.DefineLabel() }) - .ToArray(); - - foreach (var item in labels) + if (item.def.MethodInfo.ReturnType == typeof(Task) || item.def.MethodInfo.ReturnType == typeof(ValueTask)) { - // if( == ) goto ... - il.Emit(OpCodes.Ldarg_1); - il.EmitLdc_I4(item.def.MethodId); - il.Emit(OpCodes.Beq, item.label); + // Task methods uses TaskCompletionSource + responseType = typeof(Nil); } - // else - il.Emit(OpCodes.Ret); - - foreach (var item in labels) + else { - // SetResultForResponse(taskSource, data); - Type responseType; - - if (item.def.MethodInfo.ReturnType == typeof(Task) || item.def.MethodInfo.ReturnType == typeof(ValueTask)) - { - // Task methods uses TaskCompletionSource - responseType = typeof(Nil); - } - else - { - responseType = item.def.MethodInfo.ReturnType.GetGenericArguments()[0]; - } + responseType = item.def.MethodInfo.ReturnType.GetGenericArguments()[0]; + } - il.MarkLabel(item.label); + il.MarkLabel(item.label); - // this.SetResultForResponse(taskSource, data); - il.Emit(OpCodes.Ldarg_0); // this - il.Emit(OpCodes.Ldarg_2); // taskSource - il.Emit(OpCodes.Ldarg_3); // data - il.Emit(OpCodes.Call, baseType.GetMethod("SetResultForResponse", BindingFlags.Instance | BindingFlags.NonPublic)!.MakeGenericMethod(responseType)); + // this.SetResultForResponse(taskSource, data); + il.Emit(OpCodes.Ldarg_0); // this + il.Emit(OpCodes.Ldarg_2); // taskSource + il.Emit(OpCodes.Ldarg_3); // data + il.Emit(OpCodes.Call, baseType.GetMethod("SetResultForResponse", BindingFlags.Instance | BindingFlags.NonPublic)!.MakeGenericMethod(responseType)); - il.Emit(OpCodes.Ret); - } + il.Emit(OpCodes.Ret); } - // protected abstract void OnBroadcastEvent(int methodId, ReadOnlyMemory data); - { - var methodDefinitions = BroadcasterHelper.SearchDefinitions(receiverType); - BroadcasterHelper.VerifyMethodDefinitions(methodDefinitions); + } + // protected abstract void OnBroadcastEvent(int methodId, ReadOnlyMemory data); + { + var methodDefinitions = BroadcasterHelper.SearchDefinitions(receiverType); + BroadcasterHelper.VerifyMethodDefinitions(methodDefinitions); - var method = typeBuilder.DefineMethod("OnBroadcastEvent", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - typeof(void), new[] { typeof(int), typeof(ReadOnlyMemory) }); - var il = method.GetILGenerator(); + var method = typeBuilder.DefineMethod("OnBroadcastEvent", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + typeof(void), new[] { typeof(int), typeof(ReadOnlyMemory) }); + var il = method.GetILGenerator(); - var labels = methodDefinitions - .Select(x => new { def = x, label = il.DefineLabel() }) - .ToArray(); + var labels = methodDefinitions + .Select(x => new { def = x, label = il.DefineLabel() }) + .ToArray(); - foreach (var item in labels) + foreach (var item in labels) + { + // if( == ) goto ... + il.Emit(OpCodes.Ldarg_1); + il.EmitLdc_I4(item.def.MethodId); + il.Emit(OpCodes.Beq, item.label); + } + // else + il.Emit(OpCodes.Ret); + + foreach (var item in labels) + { + il.MarkLabel(item.label); + // var value = Deserialize>(data); + // receiver.OnMessage(value.Item1, value.Item2); + + var parameters = item.def.MethodInfo.GetParameters(); + if (parameters.Length == 0) { - // if( == ) goto ... - il.Emit(OpCodes.Ldarg_1); - il.EmitLdc_I4(item.def.MethodId); - il.Emit(OpCodes.Beq, item.label); + // this.receiver.OnMessage(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, receiverField); + il.Emit(OpCodes.Callvirt, item.def.MethodInfo); } - // else - il.Emit(OpCodes.Ret); - - foreach (var item in labels) + else if (parameters.Length == 1) { - il.MarkLabel(item.label); - // var value = Deserialize>(data); - // receiver.OnMessage(value.Item1, value.Item2); - - var parameters = item.def.MethodInfo.GetParameters(); - if (parameters.Length == 0) + // this.receiver.OnMessage(...); + il.Emit(OpCodes.Ldarg_0); // this. + il.Emit(OpCodes.Ldfld, receiverField); // receiver { - // this.receiver.OnMessage(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, receiverField); - il.Emit(OpCodes.Callvirt, item.def.MethodInfo); + // this.Deserialize(data) + il.Emit(OpCodes.Ldarg_0); // this + il.Emit(OpCodes.Ldarg_2); // data + il.Emit(OpCodes.Call, MethodInfoCache.StreamingHubClientBase_Deserialize.MakeGenericMethod(parameters[0].ParameterType)); } - else if (parameters.Length == 1) + il.Emit(OpCodes.Callvirt, item.def.MethodInfo); + } + else + { + var deserializeType = BroadcasterHelper.DynamicArgumentTupleTypes[parameters.Length - 2] + .MakeGenericType(parameters.Select(x => x.ParameterType).ToArray()); + var lc = il.DeclareLocal(deserializeType); + + // var local0 = this.Deserialize(data); { - // this.receiver.OnMessage(...); - il.Emit(OpCodes.Ldarg_0); // this. - il.Emit(OpCodes.Ldfld, receiverField); // receiver - { - // this.Deserialize(data) - il.Emit(OpCodes.Ldarg_0); // this - il.Emit(OpCodes.Ldarg_2); // data - il.Emit(OpCodes.Call, MethodInfoCache.StreamingHubClientBase_Deserialize.MakeGenericMethod(parameters[0].ParameterType)); - } - il.Emit(OpCodes.Callvirt, item.def.MethodInfo); + il.Emit(OpCodes.Ldarg_0); // this + il.Emit(OpCodes.Ldarg_2); // data + il.Emit(OpCodes.Call, MethodInfoCache.StreamingHubClientBase_Deserialize.MakeGenericMethod(deserializeType)); + il.Emit(OpCodes.Stloc, lc); } - else - { - var deserializeType = BroadcasterHelper.DynamicArgumentTupleTypes[parameters.Length - 2] - .MakeGenericType(parameters.Select(x => x.ParameterType).ToArray()); - var lc = il.DeclareLocal(deserializeType); - // var local0 = this.Deserialize(data); - { - il.Emit(OpCodes.Ldarg_0); // this - il.Emit(OpCodes.Ldarg_2); // data - il.Emit(OpCodes.Call, MethodInfoCache.StreamingHubClientBase_Deserialize.MakeGenericMethod(deserializeType)); - il.Emit(OpCodes.Stloc, lc); - } - - // this.receiver.OnMessage(local.Item1, local.Item2 ...); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, receiverField); - for (int i = 0; i < parameters.Length; i++) - { - il.Emit(OpCodes.Ldloc, lc); - il.Emit(OpCodes.Ldfld, deserializeType.GetField("Item" + (i + 1))!); - } - il.Emit(OpCodes.Callvirt, item.def.MethodInfo); + // this.receiver.OnMessage(local.Item1, local.Item2 ...); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, receiverField); + for (int i = 0; i < parameters.Length; i++) + { + il.Emit(OpCodes.Ldloc, lc); + il.Emit(OpCodes.Ldfld, deserializeType.GetField("Item" + (i + 1))!); } - // return; - il.Emit(OpCodes.Ret); + il.Emit(OpCodes.Callvirt, item.def.MethodInfo); } + // return; + il.Emit(OpCodes.Ret); } } - // protected abstract void OnClientResultEvent(int methodId, Guid messageId, ReadOnlyMemory data); + } + // protected abstract void OnClientResultEvent(int methodId, Guid messageId, ReadOnlyMemory data); + { + var methodDefinitions = BroadcasterHelper.SearchDefinitions(receiverType); + BroadcasterHelper.VerifyMethodDefinitions(methodDefinitions); + + var method = typeBuilder.DefineMethod("OnClientResultEvent", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + typeof(void), new[] { typeof(int), typeof(Guid), typeof(ReadOnlyMemory) }); { - var methodDefinitions = BroadcasterHelper.SearchDefinitions(receiverType); - BroadcasterHelper.VerifyMethodDefinitions(methodDefinitions); + var il = method.GetILGenerator(); + var localEx = il.DeclareLocal(typeof(Exception)); - var method = typeBuilder.DefineMethod("OnClientResultEvent", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - typeof(void), new[] { typeof(int), typeof(Guid), typeof(ReadOnlyMemory) }); + var clientResultMethods = methodDefinitions.Where(x => x.IsClientResult) + .Select(x => (Label: il.DefineLabel(), Method: x)).ToArray(); + var labelReturn = il.DefineLabel(); + + var localCtDefault = il.DeclareLocal(typeof(CancellationToken)); { - var il = method.GetILGenerator(); - var localEx = il.DeclareLocal(typeof(Exception)); + // var ctDefault = default(CancellationToken); + il.Emit(OpCodes.Ldloca_S, localCtDefault!); + il.Emit(OpCodes.Initobj, typeof(CancellationToken)); + } - var clientResultMethods = methodDefinitions.Where(x => x.IsClientResult) - .Select(x => (Label: il.DefineLabel(), Method: x)).ToArray(); - var labelReturn = il.DefineLabel(); - - var localCtDefault = il.DeclareLocal(typeof(CancellationToken)); - { - // var ctDefault = default(CancellationToken); - il.Emit(OpCodes.Ldloca_S, localCtDefault!); - il.Emit(OpCodes.Initobj, typeof(CancellationToken)); - } + // try { + il.BeginExceptionBlock(); + foreach (var (labelMethodBlock, methodClientResult) in clientResultMethods) + { + // if (methodId == ...) goto label; + il.Emit(OpCodes.Ldarg_1); // methodId + il.Emit(OpCodes.Ldc_I4, methodClientResult.MethodId); + il.Emit(OpCodes.Beq, labelMethodBlock); + } + // goto Return; + il.Emit(OpCodes.Leave, labelReturn); - // try { - il.BeginExceptionBlock(); - foreach (var (labelMethodBlock, methodClientResult) in clientResultMethods) + foreach (var (labelMethodBlock, methodClientResult) in clientResultMethods) + { + var parameters = methodClientResult.MethodInfo.GetParameters().Where(x => x.ParameterType != typeof(CancellationToken)).ToArray(); + var deserializeType = parameters.Length switch { - // if (methodId == ...) goto label; - il.Emit(OpCodes.Ldarg_1); // methodId - il.Emit(OpCodes.Ldc_I4, methodClientResult.MethodId); - il.Emit(OpCodes.Beq, labelMethodBlock); - } - // goto Return; - il.Emit(OpCodes.Leave, labelReturn); - - foreach (var (labelMethodBlock, methodClientResult) in clientResultMethods) + 0 => typeof(MessagePack.Nil), + 1 => parameters[0].ParameterType, + _ => BroadcasterHelper.DynamicArgumentTupleTypes[parameters.Length - 2].MakeGenericType(parameters.Select(x => x.ParameterType).ToArray()) + }; + + // Method: + // { + // var local_0 = base.Deserialize(data); + // var task = this.SomeMethod(local0.Item1, local0.Item2); + // base.AwaitAndWriteClientResultResponseMessage(methodId, messageId, localTask); + // return; + // } + // break; + + // Method: + il.MarkLabel(labelMethodBlock); + // var local0 = base.Deserialize(data); + il.Emit(OpCodes.Ldarg_0); // base + il.Emit(OpCodes.Ldarg_3); // data + il.Emit(OpCodes.Call, MethodInfoCache.StreamingHubClientBase_Deserialize.MakeGenericMethod(deserializeType)); + var local0 = il.DeclareLocal(deserializeType); + il.Emit(OpCodes.Stloc_S, local0); + + // var task = receiver.SomeMethod(local0.Item1, local0.Item2); + il.Emit(OpCodes.Ldarg_0); // receiver + il.Emit(OpCodes.Ldfld, receiverField); + + if (parameters.Length == 0) { - var parameters = methodClientResult.MethodInfo.GetParameters().Where(x => x.ParameterType != typeof(CancellationToken)).ToArray(); - var deserializeType = parameters.Length switch + foreach (var p in methodClientResult.MethodInfo.GetParameters()) { - 0 => typeof(MessagePack.Nil), - 1 => parameters[0].ParameterType, - _ => BroadcasterHelper.DynamicArgumentTupleTypes[parameters.Length - 2].MakeGenericType(parameters.Select(x => x.ParameterType).ToArray()) - }; - - // Method: - // { - // var local_0 = base.Deserialize(data); - // var task = this.SomeMethod(local0.Item1, local0.Item2); - // base.AwaitAndWriteClientResultResponseMessage(methodId, messageId, localTask); - // return; - // } - // break; - - // Method: - il.MarkLabel(labelMethodBlock); - // var local0 = base.Deserialize(data); - il.Emit(OpCodes.Ldarg_0); // base - il.Emit(OpCodes.Ldarg_3); // data - il.Emit(OpCodes.Call, MethodInfoCache.StreamingHubClientBase_Deserialize.MakeGenericMethod(deserializeType)); - var local0 = il.DeclareLocal(deserializeType); - il.Emit(OpCodes.Stloc_S, local0); - - // var task = receiver.SomeMethod(local0.Item1, local0.Item2); - il.Emit(OpCodes.Ldarg_0); // receiver - il.Emit(OpCodes.Ldfld, receiverField); - - if (parameters.Length == 0) + // default(CancellationToken) + il.Emit(OpCodes.Ldloca_S, localCtDefault!); + il.Emit(OpCodes.Initobj, typeof(CancellationToken)); + il.Emit(OpCodes.Ldloc_S, localCtDefault!); + } + } + else if (parameters.Length == 1) + { + foreach (var p in methodClientResult.MethodInfo.GetParameters()) { - foreach (var p in methodClientResult.MethodInfo.GetParameters()) + if (p.ParameterType == typeof(CancellationToken)) { // default(CancellationToken) il.Emit(OpCodes.Ldloca_S, localCtDefault!); il.Emit(OpCodes.Initobj, typeof(CancellationToken)); il.Emit(OpCodes.Ldloc_S, localCtDefault!); } - } - else if (parameters.Length == 1) - { - foreach (var p in methodClientResult.MethodInfo.GetParameters()) + else if (p == parameters[0]) { - if (p.ParameterType == typeof(CancellationToken)) - { - // default(CancellationToken) - il.Emit(OpCodes.Ldloca_S, localCtDefault!); - il.Emit(OpCodes.Initobj, typeof(CancellationToken)); - il.Emit(OpCodes.Ldloc_S, localCtDefault!); - } - else if (p == parameters[0]) - { - // local0 - il.Emit(OpCodes.Ldloc_S, local0); - } - else - { - throw new InvalidOperationException(); - } + // local0 + il.Emit(OpCodes.Ldloc_S, local0); + } + else + { + throw new InvalidOperationException(); } } - else + } + else + { + var itemIndex = 1; + foreach (var p in methodClientResult.MethodInfo.GetParameters()) { - var itemIndex = 1; - foreach (var p in methodClientResult.MethodInfo.GetParameters()) + if (p.ParameterType == typeof(CancellationToken)) { - if (p.ParameterType == typeof(CancellationToken)) - { - // default(CancellationToken) - il.Emit(OpCodes.Ldloca_S, localCtDefault!); - il.Emit(OpCodes.Initobj, typeof(CancellationToken)); - il.Emit(OpCodes.Ldloc_S, localCtDefault!); - } - else - { - // local0.ItemX - il.Emit(OpCodes.Ldloc_S, local0); - il.Emit(OpCodes.Ldfld, deserializeType.GetField($"Item{itemIndex}")!); - itemIndex++; - } + // default(CancellationToken) + il.Emit(OpCodes.Ldloca_S, localCtDefault!); + il.Emit(OpCodes.Initobj, typeof(CancellationToken)); + il.Emit(OpCodes.Ldloc_S, localCtDefault!); + } + else + { + // local0.ItemX + il.Emit(OpCodes.Ldloc_S, local0); + il.Emit(OpCodes.Ldfld, deserializeType.GetField($"Item{itemIndex}")!); + itemIndex++; } } - il.Emit(OpCodes.Callvirt, methodClientResult.MethodInfo); + } + il.Emit(OpCodes.Callvirt, methodClientResult.MethodInfo); - // var localTask = task; - var localTask = il.DeclareLocal(methodClientResult.MethodInfo.ReturnType); - il.Emit(OpCodes.Stloc_S, localTask); + // var localTask = task; + var localTask = il.DeclareLocal(methodClientResult.MethodInfo.ReturnType); + il.Emit(OpCodes.Stloc_S, localTask); - // base.AwaitAndWriteClientResultResponseMessage(methodId, messageId, localTask); - il.Emit(OpCodes.Ldarg_0); // base - il.Emit(OpCodes.Ldarg_1); // methodId - il.Emit(OpCodes.Ldarg_2); // messageId - il.Emit(OpCodes.Ldloc_S, localTask); - il.Emit(OpCodes.Call, MethodInfoCache.GetStreamingHubClientBase_AwaitAndWriteClientResultResponseMessage(methodClientResult.MethodInfo.ReturnType)); + // base.AwaitAndWriteClientResultResponseMessage(methodId, messageId, localTask); + il.Emit(OpCodes.Ldarg_0); // base + il.Emit(OpCodes.Ldarg_1); // methodId + il.Emit(OpCodes.Ldarg_2); // messageId + il.Emit(OpCodes.Ldloc_S, localTask); + il.Emit(OpCodes.Call, MethodInfoCache.GetStreamingHubClientBase_AwaitAndWriteClientResultResponseMessage(methodClientResult.MethodInfo.ReturnType)); - il.Emit(OpCodes.Leave, labelReturn); - } - // } catch (Exception ex) { - il.BeginCatchBlock(typeof(Exception)); - il.Emit(OpCodes.Stloc_S, localEx); - { - // base.WriteClientResultResponseMessageForError(methodId, messageId, ex); - il.Emit(OpCodes.Ldarg_0); // base - il.Emit(OpCodes.Ldarg_1); // methodId - il.Emit(OpCodes.Ldarg_2); // messageId - il.Emit(OpCodes.Ldloc_S, localEx); // ex - il.Emit(OpCodes.Call, MethodInfoCache.StreamingHubClientBase_WriteClientResultResponseMessageForError); - il.Emit(OpCodes.Leave, labelReturn); - } - il.EndExceptionBlock(); - // } - - // Return: - // return; - il.MarkLabel(labelReturn); - il.Emit(OpCodes.Ret); + il.Emit(OpCodes.Leave, labelReturn); } - } + // } catch (Exception ex) { + il.BeginCatchBlock(typeof(Exception)); + il.Emit(OpCodes.Stloc_S, localEx); + { + // base.WriteClientResultResponseMessageForError(methodId, messageId, ex); + il.Emit(OpCodes.Ldarg_0); // base + il.Emit(OpCodes.Ldarg_1); // methodId + il.Emit(OpCodes.Ldarg_2); // messageId + il.Emit(OpCodes.Ldloc_S, localEx); // ex + il.Emit(OpCodes.Call, MethodInfoCache.StreamingHubClientBase_WriteClientResultResponseMessageForError); + il.Emit(OpCodes.Leave, labelReturn); + } + il.EndExceptionBlock(); + // } - // Proxy Methods - for (int i = 0; i < definitions.Length; i++) - { - var def = definitions[i]; - var parameters = def.MethodInfo.GetParameters().Select(x => x.ParameterType).ToArray(); + // Return: + // return; + il.MarkLabel(labelReturn); + il.Emit(OpCodes.Ret); + } + } - var method = typeBuilder.DefineMethod(def.MethodInfo.Name, MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - def.MethodInfo.ReturnType, - parameters); - var il = method.GetILGenerator(); + // Proxy Methods + for (int i = 0; i < definitions.Length; i++) + { + var def = definitions[i]; + var parameters = def.MethodInfo.GetParameters().Select(x => x.ParameterType).ToArray(); - // return WriteMessageAsync(methodId, message); - // return WriteMessageWithResponseAsync(methodId, message); + var method = typeBuilder.DefineMethod(def.MethodInfo.Name, MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + def.MethodInfo.ReturnType, + parameters); + var il = method.GetILGenerator(); - // this.*** - il.Emit(OpCodes.Ldarg_0); + // return WriteMessageAsync(methodId, message); + // return WriteMessageWithResponseAsync(methodId, message); - // arg1 - il.EmitLdc_I4(def.MethodId); + // this.*** + il.Emit(OpCodes.Ldarg_0); - // create request for arg2 - for (int j = 0; j < parameters.Length; j++) - { - il.Emit(OpCodes.Ldarg, j + 1); - } + // arg1 + il.EmitLdc_I4(def.MethodId); - Type callType; - if (parameters.Length == 0) - { - // use Nil. - callType = typeof(Nil); - il.Emit(OpCodes.Ldsfld, typeof(Nil).GetField("Default")!); - } - else if (parameters.Length == 1) - { - // already loaded parameter. - callType = parameters[0]; - } - else - { - // call new DynamicArgumentTuple - callType = def.RequestType!; - il.Emit(OpCodes.Newobj, callType.GetConstructors().First()); - } + // create request for arg2 + for (int j = 0; j < parameters.Length; j++) + { + il.Emit(OpCodes.Ldarg, j + 1); + } - if (def.MethodInfo.ReturnType == typeof(Task)) - { - il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageWithResponseTaskAsync.MakeGenericMethod(callType, typeof(Nil))); - } - else if (def.MethodInfo.ReturnType == typeof(ValueTask)) - { - il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageWithResponseValueTaskAsync.MakeGenericMethod(callType, typeof(Nil))); - } - else if (def.MethodInfo.ReturnType == typeof(void)) - { - il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetValueTaskOfTAsync.MakeGenericMethod(callType, typeof(Nil))); - il.Emit(OpCodes.Pop); - } - else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) - { - il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageWithResponseValueTaskOfTAsync.MakeGenericMethod(callType, def.MethodInfo.ReturnType.GetGenericArguments()[0])); - } - else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) - { - il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageWithResponseTaskAsync.MakeGenericMethod(callType, def.MethodInfo.ReturnType.GetGenericArguments()[0])); - } + Type callType; + if (parameters.Length == 0) + { + // use Nil. + callType = typeof(Nil); + il.Emit(OpCodes.Ldsfld, typeof(Nil).GetField("Default")!); + } + else if (parameters.Length == 1) + { + // already loaded parameter. + callType = parameters[0]; + } + else + { + // call new DynamicArgumentTuple + callType = def.RequestType!; + il.Emit(OpCodes.Newobj, callType.GetConstructors().First()); + } - il.Emit(OpCodes.Ret); + if (def.MethodInfo.ReturnType == typeof(Task)) + { + il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageWithResponseTaskAsync.MakeGenericMethod(callType, typeof(Nil))); + } + else if (def.MethodInfo.ReturnType == typeof(ValueTask)) + { + il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageWithResponseValueTaskAsync.MakeGenericMethod(callType, typeof(Nil))); } + else if (def.MethodInfo.ReturnType == typeof(void)) + { + il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetValueTaskOfTAsync.MakeGenericMethod(callType, typeof(Nil))); + il.Emit(OpCodes.Pop); + } + else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) + { + il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageWithResponseValueTaskOfTAsync.MakeGenericMethod(callType, def.MethodInfo.ReturnType.GetGenericArguments()[0])); + } + else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) + { + il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageWithResponseTaskAsync.MakeGenericMethod(callType, def.MethodInfo.ReturnType.GetGenericArguments()[0])); + } + + il.Emit(OpCodes.Ret); } + } - static void DefineMethodsFireAndForget(TypeBuilder typeBuilder, Type interfaceType, FieldInfo clientField, Type parentNestedType, MethodDefinition[] definitions) + static void DefineMethodsFireAndForget(TypeBuilder typeBuilder, Type interfaceType, FieldInfo clientField, Type parentNestedType, MethodDefinition[] definitions) + { { + // Task DisposeAsync(); { - // Task DisposeAsync(); - { - var method = typeBuilder.DefineMethod("DisposeAsync", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - typeof(Task), Type.EmptyTypes); - var il = method.GetILGenerator(); - - il.Emit(OpCodes.Newobj, notSupportedException); - il.Emit(OpCodes.Throw); - } - // Task WaitForDisconnect(); - { - var method = typeBuilder.DefineMethod("WaitForDisconnect", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - typeof(Task), Type.EmptyTypes); - var il = method.GetILGenerator(); - - il.Emit(OpCodes.Newobj, notSupportedException); - il.Emit(OpCodes.Throw); - } - // TSelf FireAndForget(); - { - var method = typeBuilder.DefineMethod("FireAndForget", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - interfaceType, Type.EmptyTypes); - var il = method.GetILGenerator(); + var method = typeBuilder.DefineMethod("DisposeAsync", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + typeof(Task), Type.EmptyTypes); + var il = method.GetILGenerator(); - il.Emit(OpCodes.Newobj, notSupportedException); - il.Emit(OpCodes.Throw); - } + il.Emit(OpCodes.Newobj, notSupportedException); + il.Emit(OpCodes.Throw); } - - // Proxy Methods - for (int i = 0; i < definitions.Length; i++) + // Task WaitForDisconnect(); { - var def = definitions[i]; - var parameters = def.MethodInfo.GetParameters().Select(x => x.ParameterType).ToArray(); + var method = typeBuilder.DefineMethod("WaitForDisconnect", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + typeof(Task), Type.EmptyTypes); + var il = method.GetILGenerator(); - var method = typeBuilder.DefineMethod(def.MethodInfo.Name, MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, - def.MethodInfo.ReturnType, - parameters); + il.Emit(OpCodes.Newobj, notSupportedException); + il.Emit(OpCodes.Throw); + } + // TSelf FireAndForget(); + { + var method = typeBuilder.DefineMethod("FireAndForget", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + interfaceType, Type.EmptyTypes); var il = method.GetILGenerator(); - // return client.WriteMessageAsyncFireAndForget(methodId, message); + il.Emit(OpCodes.Newobj, notSupportedException); + il.Emit(OpCodes.Throw); + } + } - // this.client.*** - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, clientField); + // Proxy Methods + for (int i = 0; i < definitions.Length; i++) + { + var def = definitions[i]; + var parameters = def.MethodInfo.GetParameters().Select(x => x.ParameterType).ToArray(); - // arg1 - il.EmitLdc_I4(def.MethodId); + var method = typeBuilder.DefineMethod(def.MethodInfo.Name, MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual, + def.MethodInfo.ReturnType, + parameters); + var il = method.GetILGenerator(); - // create request for arg2 - for (int j = 0; j < parameters.Length; j++) - { - il.Emit(OpCodes.Ldarg, j + 1); - } + // return client.WriteMessageAsyncFireAndForget(methodId, message); - Type requestType; - if (parameters.Length == 0) - { - // use Nil. - requestType = typeof(Nil); - il.Emit(OpCodes.Ldsfld, typeof(Nil).GetField("Default")!); - } - else if (parameters.Length == 1) - { - // already loaded parameter. - requestType = parameters[0]; - } - else - { - // call new DynamicArgumentTuple - requestType = def.RequestType!; - il.Emit(OpCodes.Newobj, requestType.GetConstructors().First()); - } + // this.client.*** + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldfld, clientField); - Type responseType; - if (def.MethodInfo.ReturnType == typeof(Task) || def.MethodInfo.ReturnType == typeof(ValueTask) || def.MethodInfo.ReturnType == typeof(void)) - { - responseType = typeof(Nil); - } - else - { - responseType = def.MethodInfo.ReturnType.GetGenericArguments()[0]; - } + // arg1 + il.EmitLdc_I4(def.MethodId); - if (def.MethodInfo.ReturnType == typeof(Task)) - { - il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetTaskAsync.MakeGenericMethod(requestType, responseType)); - } - else if (def.MethodInfo.ReturnType == typeof(ValueTask)) - { - il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetValueTaskAsync.MakeGenericMethod(requestType, responseType)); - } - else if (def.MethodInfo.ReturnType == typeof(void)) - { - il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetValueTaskOfTAsync.MakeGenericMethod(requestType, responseType)); - il.Emit(OpCodes.Pop); - } - else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) - { - il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetValueTaskOfTAsync.MakeGenericMethod(requestType, responseType)); - } - else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) - { - il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetTaskAsync.MakeGenericMethod(requestType, responseType)); - } - else - { - throw new NotSupportedException($"Unsupported Return Type: {def.MethodInfo.ReturnType}"); - } + // create request for arg2 + for (int j = 0; j < parameters.Length; j++) + { + il.Emit(OpCodes.Ldarg, j + 1); + } - il.Emit(OpCodes.Ret); + Type requestType; + if (parameters.Length == 0) + { + // use Nil. + requestType = typeof(Nil); + il.Emit(OpCodes.Ldsfld, typeof(Nil).GetField("Default")!); } + else if (parameters.Length == 1) + { + // already loaded parameter. + requestType = parameters[0]; + } + else + { + // call new DynamicArgumentTuple + requestType = def.RequestType!; + il.Emit(OpCodes.Newobj, requestType.GetConstructors().First()); + } + + Type responseType; + if (def.MethodInfo.ReturnType == typeof(Task) || def.MethodInfo.ReturnType == typeof(ValueTask) || def.MethodInfo.ReturnType == typeof(void)) + { + responseType = typeof(Nil); + } + else + { + responseType = def.MethodInfo.ReturnType.GetGenericArguments()[0]; + } + + if (def.MethodInfo.ReturnType == typeof(Task)) + { + il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetTaskAsync.MakeGenericMethod(requestType, responseType)); + } + else if (def.MethodInfo.ReturnType == typeof(ValueTask)) + { + il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetValueTaskAsync.MakeGenericMethod(requestType, responseType)); + } + else if (def.MethodInfo.ReturnType == typeof(void)) + { + il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetValueTaskOfTAsync.MakeGenericMethod(requestType, responseType)); + il.Emit(OpCodes.Pop); + } + else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) + { + il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetValueTaskOfTAsync.MakeGenericMethod(requestType, responseType)); + } + else if (def.MethodInfo.ReturnType.IsGenericType && def.MethodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) + { + il.Emit(OpCodes.Callvirt, MethodInfoCache.StreamingHubClientBase_WriteMessageFireAndForgetTaskAsync.MakeGenericMethod(requestType, responseType)); + } + else + { + throw new NotSupportedException($"Unsupported Return Type: {def.MethodInfo.ReturnType}"); + } + + il.Emit(OpCodes.Ret); } + } - [RequiresUnreferencedCode(nameof(MethodInfoCache) + " is incompatible with trimming and Native AOT.")] - static class MethodInfoCache - { - // ReSharper disable StaticMemberInGenericType - // ReSharper disable InconsistentNaming + [RequiresUnreferencedCode(nameof(MethodInfoCache) + " is incompatible with trimming and Native AOT.")] + static class MethodInfoCache + { + // ReSharper disable StaticMemberInGenericType + // ReSharper disable InconsistentNaming #pragma warning disable IDE1006 // Naming Styles - public static readonly MethodInfo StreamingHubClientBase_Deserialize - = typeof(StreamingHubClientBase).GetMethod("Deserialize", BindingFlags.Instance | BindingFlags.NonPublic)!; - - static readonly MethodInfo StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_Task; - static readonly MethodInfo StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_TaskOfT; - static readonly MethodInfo StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTask; - static readonly MethodInfo StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTaskOfT; - - public static MethodInfo GetStreamingHubClientBase_AwaitAndWriteClientResultResponseMessage(Type t) - => t == typeof(Task) ? StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_Task - : t == typeof(ValueTask) ? StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTask - : t.GetGenericTypeDefinition() == typeof(Task<>) ? StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_TaskOfT.MakeGenericMethod(t.GetGenericArguments()) - : t.GetGenericTypeDefinition() == typeof(ValueTask<>) ? StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTaskOfT.MakeGenericMethod(t.GetGenericArguments()) - : throw new InvalidOperationException(); - - public static readonly MethodInfo StreamingHubClientBase_WriteClientResultResponseMessageForError - = typeof(StreamingHubClientBase).GetMethod("WriteClientResultResponseMessageForError", BindingFlags.NonPublic | BindingFlags.Instance)!; - public static readonly MethodInfo StreamingHubClientBase_WriteMessageWithResponseValueTaskOfTAsync - = typeof(StreamingHubClientBase).GetMethod("WriteMessageWithResponseValueTaskOfTAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; - public static readonly MethodInfo StreamingHubClientBase_WriteMessageWithResponseTaskAsync - = typeof(StreamingHubClientBase).GetMethod("WriteMessageWithResponseTaskAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; - public static readonly MethodInfo StreamingHubClientBase_WriteMessageWithResponseValueTaskAsync - = typeof(StreamingHubClientBase).GetMethod("WriteMessageWithResponseValueTaskAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; - public static readonly MethodInfo StreamingHubClientBase_WriteMessageFireAndForgetValueTaskOfTAsync - = typeof(StreamingHubClientBase).GetMethod("WriteMessageFireAndForgetValueTaskOfTAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; - public static readonly MethodInfo StreamingHubClientBase_WriteMessageFireAndForgetValueTaskAsync - = typeof(StreamingHubClientBase).GetMethod("WriteMessageFireAndForgetValueTaskAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; - public static readonly MethodInfo StreamingHubClientBase_WriteMessageFireAndForgetTaskAsync - = typeof(StreamingHubClientBase).GetMethod("WriteMessageFireAndForgetTaskAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; - // ReSharper restore StaticMemberInGenericType - // ReSharper restore InconsistentNaming + public static readonly MethodInfo StreamingHubClientBase_Deserialize + = typeof(StreamingHubClientBase).GetMethod("Deserialize", BindingFlags.Instance | BindingFlags.NonPublic)!; + + static readonly MethodInfo StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_Task; + static readonly MethodInfo StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_TaskOfT; + static readonly MethodInfo StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTask; + static readonly MethodInfo StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTaskOfT; + + public static MethodInfo GetStreamingHubClientBase_AwaitAndWriteClientResultResponseMessage(Type t) + => t == typeof(Task) ? StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_Task + : t == typeof(ValueTask) ? StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTask + : t.GetGenericTypeDefinition() == typeof(Task<>) ? StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_TaskOfT.MakeGenericMethod(t.GetGenericArguments()) + : t.GetGenericTypeDefinition() == typeof(ValueTask<>) ? StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTaskOfT.MakeGenericMethod(t.GetGenericArguments()) + : throw new InvalidOperationException(); + + public static readonly MethodInfo StreamingHubClientBase_WriteClientResultResponseMessageForError + = typeof(StreamingHubClientBase).GetMethod("WriteClientResultResponseMessageForError", BindingFlags.NonPublic | BindingFlags.Instance)!; + public static readonly MethodInfo StreamingHubClientBase_WriteMessageWithResponseValueTaskOfTAsync + = typeof(StreamingHubClientBase).GetMethod("WriteMessageWithResponseValueTaskOfTAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; + public static readonly MethodInfo StreamingHubClientBase_WriteMessageWithResponseTaskAsync + = typeof(StreamingHubClientBase).GetMethod("WriteMessageWithResponseTaskAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; + public static readonly MethodInfo StreamingHubClientBase_WriteMessageWithResponseValueTaskAsync + = typeof(StreamingHubClientBase).GetMethod("WriteMessageWithResponseValueTaskAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; + public static readonly MethodInfo StreamingHubClientBase_WriteMessageFireAndForgetValueTaskOfTAsync + = typeof(StreamingHubClientBase).GetMethod("WriteMessageFireAndForgetValueTaskOfTAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; + public static readonly MethodInfo StreamingHubClientBase_WriteMessageFireAndForgetValueTaskAsync + = typeof(StreamingHubClientBase).GetMethod("WriteMessageFireAndForgetValueTaskAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; + public static readonly MethodInfo StreamingHubClientBase_WriteMessageFireAndForgetTaskAsync + = typeof(StreamingHubClientBase).GetMethod("WriteMessageFireAndForgetTaskAsync", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!; + // ReSharper restore StaticMemberInGenericType + // ReSharper restore InconsistentNaming #pragma warning restore IDE1006 // Naming Styles - static MethodInfoCache() - { - var methodsAwaitAndWriteClientResultResponseMessage = typeof(StreamingHubClientBase) - .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) - .Where(x => x.Name == "AwaitAndWriteClientResultResponseMessage") - .ToArray(); + static MethodInfoCache() + { + var methodsAwaitAndWriteClientResultResponseMessage = typeof(StreamingHubClientBase) + .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) + .Where(x => x.Name == "AwaitAndWriteClientResultResponseMessage") + .ToArray(); - StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_Task = methodsAwaitAndWriteClientResultResponseMessage.Single(x => x.GetParameters()[2].ParameterType == typeof(Task)); - StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_TaskOfT = methodsAwaitAndWriteClientResultResponseMessage.Single(x => x.GetParameters()[2].ParameterType is { IsGenericType: true } paramType && paramType.GetGenericTypeDefinition() == typeof(Task<>)); - StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTask = methodsAwaitAndWriteClientResultResponseMessage.Single(x => x.GetParameters()[2].ParameterType == typeof(ValueTask)); - StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTaskOfT = methodsAwaitAndWriteClientResultResponseMessage.Single(x => x.GetParameters()[2].ParameterType is { IsGenericType: true } paramType && paramType.GetGenericTypeDefinition() == typeof(ValueTask<>)); - } + StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_Task = methodsAwaitAndWriteClientResultResponseMessage.Single(x => x.GetParameters()[2].ParameterType == typeof(Task)); + StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_TaskOfT = methodsAwaitAndWriteClientResultResponseMessage.Single(x => x.GetParameters()[2].ParameterType is { IsGenericType: true } paramType && paramType.GetGenericTypeDefinition() == typeof(Task<>)); + StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTask = methodsAwaitAndWriteClientResultResponseMessage.Single(x => x.GetParameters()[2].ParameterType == typeof(ValueTask)); + StreamingHubClientBase_AwaitAndWriteClientResultResponseMessage_ValueTaskOfT = methodsAwaitAndWriteClientResultResponseMessage.Single(x => x.GetParameters()[2].ParameterType is { IsGenericType: true } paramType && paramType.GetGenericTypeDefinition() == typeof(ValueTask<>)); } + } - class MethodDefinition - { - public string Path => ServiceType.Name + "/" + MethodInfo.Name; + class MethodDefinition + { + public string Path => ServiceType.Name + "/" + MethodInfo.Name; - public Type ServiceType { get; set; } - public MethodInfo MethodInfo { get; set; } - public int MethodId { get; set; } + public Type ServiceType { get; set; } + public MethodInfo MethodInfo { get; set; } + public int MethodId { get; set; } - public Type? RequestType { get; set; } + public Type? RequestType { get; set; } - public MethodDefinition(Type serviceType, MethodInfo methodInfo, int methodId, Type? requestType) - { - ServiceType = serviceType; - MethodInfo = methodInfo; - MethodId = methodId; - RequestType = requestType; - } + public MethodDefinition(Type serviceType, MethodInfo methodInfo, int methodId, Type? requestType) + { + ServiceType = serviceType; + MethodInfo = methodInfo; + MethodId = methodId; + RequestType = requestType; } } } diff --git a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs index 4e2b59443..ebcd44b7d 100644 --- a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs +++ b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs @@ -1,37 +1,36 @@ using System.Diagnostics.CodeAnalysis; -namespace MagicOnion.Client.DynamicClient +namespace MagicOnion.Client.DynamicClient; + +public class DynamicNotSupportedStreamingHubClientFactoryProvider : IStreamingHubClientFactoryProvider { - public class DynamicNotSupportedStreamingHubClientFactoryProvider : IStreamingHubClientFactoryProvider + public static IStreamingHubClientFactoryProvider Instance { get; } = new DynamicNotSupportedStreamingHubClientFactoryProvider(); + + DynamicNotSupportedStreamingHubClientFactoryProvider() { } + + public bool TryGetFactory([NotNullWhen(true)] out StreamingHubClientFactoryDelegate? factory) where TStreamingHub : IStreamingHub { - public static IStreamingHubClientFactoryProvider Instance { get; } = new DynamicNotSupportedStreamingHubClientFactoryProvider(); + throw new InvalidOperationException($"Unable to find a client factory of type '{typeof(TStreamingHub)}'. If the application is running on IL2CPP or AOT, dynamic code generation is not supported. Please use the code generator (moc)."); + } +} + +[RequiresUnreferencedCode(nameof(DynamicStreamingHubClientFactoryProvider) + " is incompatible with trimming and Native AOT.")] +public class DynamicStreamingHubClientFactoryProvider : IStreamingHubClientFactoryProvider +{ + public static IStreamingHubClientFactoryProvider Instance { get; } = new DynamicStreamingHubClientFactoryProvider(); - DynamicNotSupportedStreamingHubClientFactoryProvider() { } + DynamicStreamingHubClientFactoryProvider() { } - public bool TryGetFactory([NotNullWhen(true)] out StreamingHubClientFactoryDelegate? factory) where TStreamingHub : IStreamingHub - { - throw new InvalidOperationException($"Unable to find a client factory of type '{typeof(TStreamingHub)}'. If the application is running on IL2CPP or AOT, dynamic code generation is not supported. Please use the code generator (moc)."); - } + public bool TryGetFactory([NotNullWhen(true)] out StreamingHubClientFactoryDelegate? factory) where TStreamingHub : IStreamingHub + { + factory = Cache.Factory; + return true; } - [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientFactoryProvider) + " is incompatible with trimming and Native AOT.")] - public class DynamicStreamingHubClientFactoryProvider : IStreamingHubClientFactoryProvider + [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientFactoryProvider) + "." + nameof(Cache) + " is incompatible with trimming and Native AOT.")] + static class Cache where TStreamingHub : IStreamingHub { - public static IStreamingHubClientFactoryProvider Instance { get; } = new DynamicStreamingHubClientFactoryProvider(); - - DynamicStreamingHubClientFactoryProvider() { } - - public bool TryGetFactory([NotNullWhen(true)] out StreamingHubClientFactoryDelegate? factory) where TStreamingHub : IStreamingHub - { - factory = Cache.Factory; - return true; - } - - [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientFactoryProvider) + "." + nameof(Cache) + " is incompatible with trimming and Native AOT.")] - static class Cache where TStreamingHub : IStreamingHub - { - public static readonly StreamingHubClientFactoryDelegate Factory - = (receiver, callInvoker, options) => (TStreamingHub)Activator.CreateInstance(DynamicStreamingHubClientBuilder.ClientType, receiver, callInvoker, options)!; - } + public static readonly StreamingHubClientFactoryDelegate Factory + = (receiver, callInvoker, options) => (TStreamingHub)Activator.CreateInstance(DynamicStreamingHubClientBuilder.ClientType, receiver, callInvoker, options)!; } } diff --git a/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs b/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs index a0bc47ce6..f55babb82 100644 --- a/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs +++ b/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs @@ -2,32 +2,31 @@ using System.Reflection; using MagicOnion.Client.Internal; -namespace MagicOnion.Client.DynamicClient +namespace MagicOnion.Client.DynamicClient; + +[RequiresUnreferencedCode(nameof(RawMethodInvokerTypes) + " is incompatible with trimming and Native AOT.")] +internal static class RawMethodInvokerTypes { - [RequiresUnreferencedCode(nameof(RawMethodInvokerTypes) + " is incompatible with trimming and Native AOT.")] - internal static class RawMethodInvokerTypes - { - static readonly MethodInfo create_RefType_RefType = typeof(RawMethodInvoker).GetMethod(nameof(RawMethodInvoker.Create_RefType_RefType), BindingFlags.Static | BindingFlags.Public)!; - static readonly MethodInfo create_RefType_ValueType = typeof(RawMethodInvoker).GetMethod(nameof(RawMethodInvoker.Create_RefType_ValueType), BindingFlags.Static | BindingFlags.Public)!; - static readonly MethodInfo create_ValueType_RefType = typeof(RawMethodInvoker).GetMethod(nameof(RawMethodInvoker.Create_ValueType_RefType), BindingFlags.Static | BindingFlags.Public)!; - static readonly MethodInfo create_ValueType_ValueType = typeof(RawMethodInvoker).GetMethod(nameof(RawMethodInvoker.Create_ValueType_ValueType), BindingFlags.Static | BindingFlags.Public)!; + static readonly MethodInfo create_RefType_RefType = typeof(RawMethodInvoker).GetMethod(nameof(RawMethodInvoker.Create_RefType_RefType), BindingFlags.Static | BindingFlags.Public)!; + static readonly MethodInfo create_RefType_ValueType = typeof(RawMethodInvoker).GetMethod(nameof(RawMethodInvoker.Create_RefType_ValueType), BindingFlags.Static | BindingFlags.Public)!; + static readonly MethodInfo create_ValueType_RefType = typeof(RawMethodInvoker).GetMethod(nameof(RawMethodInvoker.Create_ValueType_RefType), BindingFlags.Static | BindingFlags.Public)!; + static readonly MethodInfo create_ValueType_ValueType = typeof(RawMethodInvoker).GetMethod(nameof(RawMethodInvoker.Create_ValueType_ValueType), BindingFlags.Static | BindingFlags.Public)!; - public static MethodInfo GetMethodRawInvokerCreateMethod(Type requestType, Type responseType) + public static MethodInfo GetMethodRawInvokerCreateMethod(Type requestType, Type responseType) + { + if (requestType.IsValueType && responseType.IsValueType) { - if (requestType.IsValueType && responseType.IsValueType) - { - return create_ValueType_ValueType.MakeGenericMethod(requestType, responseType); - } - else if (requestType.IsValueType) - { - return create_ValueType_RefType.MakeGenericMethod(requestType, responseType); - } - else if (responseType.IsValueType) - { - return create_RefType_ValueType.MakeGenericMethod(requestType, responseType); - } - - return create_RefType_RefType.MakeGenericMethod(requestType, responseType); + return create_ValueType_ValueType.MakeGenericMethod(requestType, responseType); } + else if (requestType.IsValueType) + { + return create_ValueType_RefType.MakeGenericMethod(requestType, responseType); + } + else if (responseType.IsValueType) + { + return create_RefType_ValueType.MakeGenericMethod(requestType, responseType); + } + + return create_RefType_RefType.MakeGenericMethod(requestType, responseType); } } diff --git a/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs b/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs index 44c54d0da..62565af08 100644 --- a/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs +++ b/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs @@ -4,233 +4,232 @@ using Grpc.Core; using MessagePack; -namespace MagicOnion.Client.DynamicClient +namespace MagicOnion.Client.DynamicClient; + +[RequiresUnreferencedCode(nameof(ServiceClientDefinition) + " is incompatible with trimming and Native AOT.")] +internal class ServiceClientDefinition { - [RequiresUnreferencedCode(nameof(ServiceClientDefinition) + " is incompatible with trimming and Native AOT.")] - internal class ServiceClientDefinition + public Type ServiceInterfaceType { get; } + public IReadOnlyList Methods { get; } + + public ServiceClientDefinition(Type serviceInterfaceType, IReadOnlyList methods) + { + ServiceInterfaceType = serviceInterfaceType; + Methods = methods; + } + + [RequiresUnreferencedCode(nameof(MagicOnionServiceMethodInfo) + " is incompatible with trimming and Native AOT.")] + public class MagicOnionServiceMethodInfo { - public Type ServiceInterfaceType { get; } - public IReadOnlyList Methods { get; } + public MethodType MethodType { get; } + public string ServiceName { get; } + public string MethodName { get; } + public string Path { get; } + public IReadOnlyList ParameterTypes { get; } + public Type MethodReturnType { get; } + public Type RequestType { get; } + public Type ResponseType { get; } + + public MagicOnionServiceMethodInfo(MethodType methodType, string serviceName, string methodName, string path, IReadOnlyList parameterTypes, Type methodReturnType, Type requestType, Type responseType) + { + Debug.Assert(requestType != typeof(void)); + Debug.Assert(responseType != typeof(void)); + Debug.Assert(!(responseType.IsConstructedGenericType && (responseType.GetGenericTypeDefinition() == typeof(UnaryResult<>) || + responseType.GetGenericTypeDefinition() == typeof(ClientStreamingResult<,>) || + responseType.GetGenericTypeDefinition() == typeof(ServerStreamingResult<>) || + responseType.GetGenericTypeDefinition() == typeof(DuplexStreamingResult<,>)))); + + MethodType = methodType; + ServiceName = serviceName; + MethodName = methodName; + Path = path; + ParameterTypes = parameterTypes; + MethodReturnType = methodReturnType; + RequestType = requestType; + ResponseType = responseType; + } - public ServiceClientDefinition(Type serviceInterfaceType, IReadOnlyList methods) + public static MagicOnionServiceMethodInfo Create(Type serviceType, MethodInfo methodInfo) { - ServiceInterfaceType = serviceInterfaceType; - Methods = methods; + var (methodType, requestType, responseType) = GetMethodTypeAndResponseTypeFromMethod(methodInfo); + + var method = new MagicOnionServiceMethodInfo( + methodType, + serviceType.Name, + methodInfo.Name, + $"{serviceType.Name}/{methodInfo.Name}", + methodInfo.GetParameters().Select(y => y.ParameterType).ToArray(), + methodInfo.ReturnType, + requestType ?? GetRequestTypeFromMethod(methodInfo), + responseType + ); + method.Verify(); + + return method; } - [RequiresUnreferencedCode(nameof(MagicOnionServiceMethodInfo) + " is incompatible with trimming and Native AOT.")] - public class MagicOnionServiceMethodInfo + void Verify() { - public MethodType MethodType { get; } - public string ServiceName { get; } - public string MethodName { get; } - public string Path { get; } - public IReadOnlyList ParameterTypes { get; } - public Type MethodReturnType { get; } - public Type RequestType { get; } - public Type ResponseType { get; } - - public MagicOnionServiceMethodInfo(MethodType methodType, string serviceName, string methodName, string path, IReadOnlyList parameterTypes, Type methodReturnType, Type requestType, Type responseType) + switch (MethodType) { - Debug.Assert(requestType != typeof(void)); - Debug.Assert(responseType != typeof(void)); - Debug.Assert(!(responseType.IsConstructedGenericType && (responseType.GetGenericTypeDefinition() == typeof(UnaryResult<>) || - responseType.GetGenericTypeDefinition() == typeof(ClientStreamingResult<,>) || - responseType.GetGenericTypeDefinition() == typeof(ServerStreamingResult<>) || - responseType.GetGenericTypeDefinition() == typeof(DuplexStreamingResult<,>)))); - - MethodType = methodType; - ServiceName = serviceName; - MethodName = methodName; - Path = path; - ParameterTypes = parameterTypes; - MethodReturnType = methodReturnType; - RequestType = requestType; - ResponseType = responseType; + case MethodType.Unary: + if ((MethodReturnType != typeof(UnaryResult)) && + (MethodReturnType.IsGenericType && MethodReturnType.GetGenericTypeDefinition() != typeof(UnaryResult<>))) + { + throw new InvalidOperationException($"The return type of Unary method must be UnaryResult. (Service: {ServiceName}, Method: {MethodName})"); + } + break; + case MethodType.ClientStreaming: + break; + case MethodType.DuplexStreaming: + break; + case MethodType.ServerStreaming: + break; + default: + throw new NotSupportedException(); // Unreachable } + } + + static (MethodType MethodType, Type? RequestType, Type ResponseType) GetMethodTypeAndResponseTypeFromMethod(MethodInfo methodInfo) + { + const string UnsupportedReturnTypeErrorMessage = + "The method of a service must return 'UnaryResult', 'Task>', 'Task>' or 'DuplexStreamingResult'."; - public static MagicOnionServiceMethodInfo Create(Type serviceType, MethodInfo methodInfo) + var returnType = methodInfo.ReturnType; + if (returnType == typeof(UnaryResult)) { - var (methodType, requestType, responseType) = GetMethodTypeAndResponseTypeFromMethod(methodInfo); - - var method = new MagicOnionServiceMethodInfo( - methodType, - serviceType.Name, - methodInfo.Name, - $"{serviceType.Name}/{methodInfo.Name}", - methodInfo.GetParameters().Select(y => y.ParameterType).ToArray(), - methodInfo.ReturnType, - requestType ?? GetRequestTypeFromMethod(methodInfo), - responseType - ); - method.Verify(); - - return method; + return (MethodType.Unary, null, typeof(Nil)); } - - void Verify() + if (!returnType.IsGenericType) { - switch (MethodType) - { - case MethodType.Unary: - if ((MethodReturnType != typeof(UnaryResult)) && - (MethodReturnType.IsGenericType && MethodReturnType.GetGenericTypeDefinition() != typeof(UnaryResult<>))) - { - throw new InvalidOperationException($"The return type of Unary method must be UnaryResult. (Service: {ServiceName}, Method: {MethodName})"); - } - break; - case MethodType.ClientStreaming: - break; - case MethodType.DuplexStreaming: - break; - case MethodType.ServerStreaming: - break; - default: - throw new NotSupportedException(); // Unreachable - } + throw new InvalidOperationException($"{UnsupportedReturnTypeErrorMessage} (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); } - static (MethodType MethodType, Type? RequestType, Type ResponseType) GetMethodTypeAndResponseTypeFromMethod(MethodInfo methodInfo) + var isTaskOfT = false; + var returnTypeOpen = returnType.GetGenericTypeDefinition(); + if (returnTypeOpen == typeof(Task<>)) { - const string UnsupportedReturnTypeErrorMessage = - "The method of a service must return 'UnaryResult', 'Task>', 'Task>' or 'DuplexStreamingResult'."; - - var returnType = methodInfo.ReturnType; - if (returnType == typeof(UnaryResult)) - { - return (MethodType.Unary, null, typeof(Nil)); - } + isTaskOfT = true; + returnType = returnType.GetGenericArguments()[0]; if (!returnType.IsGenericType) { throw new InvalidOperationException($"{UnsupportedReturnTypeErrorMessage} (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); } + returnTypeOpen = returnType.GetGenericTypeDefinition(); + } - var isTaskOfT = false; - var returnTypeOpen = returnType.GetGenericTypeDefinition(); - if (returnTypeOpen == typeof(Task<>)) - { - isTaskOfT = true; - returnType = returnType.GetGenericArguments()[0]; - if (!returnType.IsGenericType) - { - throw new InvalidOperationException($"{UnsupportedReturnTypeErrorMessage} (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); - } - returnTypeOpen = returnType.GetGenericTypeDefinition(); - } - - if (returnTypeOpen == typeof(UnaryResult)) - { - if (isTaskOfT) - { - throw new InvalidOperationException($"The return type of an Unary method must be 'UnaryResult' or 'UnaryResult'. (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); - } - return (MethodType.Unary, null, typeof(Nil)); - } - else if (returnTypeOpen == typeof(UnaryResult<>)) + if (returnTypeOpen == typeof(UnaryResult)) + { + if (isTaskOfT) { - if (isTaskOfT) - { - throw new InvalidOperationException($"The return type of an Unary method must be 'UnaryResult' or 'UnaryResult'. (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); - } - return (MethodType.Unary, null, returnType.GetGenericArguments()[0]); + throw new InvalidOperationException($"The return type of an Unary method must be 'UnaryResult' or 'UnaryResult'. (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); } - else if (returnTypeOpen == typeof(ClientStreamingResult<,>)) + return (MethodType.Unary, null, typeof(Nil)); + } + else if (returnTypeOpen == typeof(UnaryResult<>)) + { + if (isTaskOfT) { - if (!isTaskOfT) - { - throw new InvalidOperationException($"The return type of a Streaming method must be 'Task'. (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); - } - return (MethodType.ClientStreaming, returnType.GetGenericArguments()[0], returnType.GetGenericArguments()[1]); + throw new InvalidOperationException($"The return type of an Unary method must be 'UnaryResult' or 'UnaryResult'. (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); } - else if (returnTypeOpen == typeof(ServerStreamingResult<>)) + return (MethodType.Unary, null, returnType.GetGenericArguments()[0]); + } + else if (returnTypeOpen == typeof(ClientStreamingResult<,>)) + { + if (!isTaskOfT) { - if (!isTaskOfT) - { - throw new InvalidOperationException($"The return type of a Streaming method must be 'Task'. (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); - } - return (MethodType.ServerStreaming, null, returnType.GetGenericArguments()[0]); // Use method parameters as response type + throw new InvalidOperationException($"The return type of a Streaming method must be 'Task'. (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); } - else if (returnTypeOpen == typeof(DuplexStreamingResult<,>)) + return (MethodType.ClientStreaming, returnType.GetGenericArguments()[0], returnType.GetGenericArguments()[1]); + } + else if (returnTypeOpen == typeof(ServerStreamingResult<>)) + { + if (!isTaskOfT) { - if (!isTaskOfT) - { - throw new InvalidOperationException($"The return type of a Streaming method must be 'Task'. (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); - } - return (MethodType.DuplexStreaming, returnType.GetGenericArguments()[0], returnType.GetGenericArguments()[1]); + throw new InvalidOperationException($"The return type of a Streaming method must be 'Task'. (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); } - else + return (MethodType.ServerStreaming, null, returnType.GetGenericArguments()[0]); // Use method parameters as response type + } + else if (returnTypeOpen == typeof(DuplexStreamingResult<,>)) + { + if (!isTaskOfT) { - throw new InvalidOperationException($"{UnsupportedReturnTypeErrorMessage} (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); + throw new InvalidOperationException($"The return type of a Streaming method must be 'Task'. (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); } + return (MethodType.DuplexStreaming, returnType.GetGenericArguments()[0], returnType.GetGenericArguments()[1]); + } + else + { + throw new InvalidOperationException($"{UnsupportedReturnTypeErrorMessage} (Method: {methodInfo.DeclaringType!.Name}.{methodInfo.Name})"); } } + } - public static ServiceClientDefinition CreateFromType() - { - return new ServiceClientDefinition(typeof(T), GetServiceMethods(typeof(T))); - } + public static ServiceClientDefinition CreateFromType() + { + return new ServiceClientDefinition(typeof(T), GetServiceMethods(typeof(T))); + } - static IReadOnlyList GetServiceMethods(Type serviceType) - { - return serviceType - .GetInterfaces() - .Concat(new[] { serviceType }) - .SelectMany(x => x.GetMethods()) - .Where(x => + static IReadOnlyList GetServiceMethods(Type serviceType) + { + return serviceType + .GetInterfaces() + .Concat(new[] { serviceType }) + .SelectMany(x => x.GetMethods()) + .Where(x => + { + var methodInfo = x; + if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_"))) return false; + if (methodInfo.GetCustomAttribute(false) != null) return false; // ignore + + var methodName = methodInfo.Name; + if (methodName == "Equals" + || methodName == "GetHashCode" + || methodName == "GetType" + || methodName == "ToString" + || methodName == "WithOptions" + || methodName == "WithHeaders" + || methodName == "WithDeadline" + || methodName == "WithCancellationToken" + || methodName == "WithHost" + ) { - var methodInfo = x; - if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_"))) return false; - if (methodInfo.GetCustomAttribute(false) != null) return false; // ignore - - var methodName = methodInfo.Name; - if (methodName == "Equals" - || methodName == "GetHashCode" - || methodName == "GetType" - || methodName == "ToString" - || methodName == "WithOptions" - || methodName == "WithHeaders" - || methodName == "WithDeadline" - || methodName == "WithCancellationToken" - || methodName == "WithHost" - ) - { - return false; - } - return true; - }) - .Where(x => !x.IsSpecialName) - .Select(x => MagicOnionServiceMethodInfo.Create(serviceType, x)) - .ToArray(); - } + return false; + } + return true; + }) + .Where(x => !x.IsSpecialName) + .Select(x => MagicOnionServiceMethodInfo.Create(serviceType, x)) + .ToArray(); + } - /// - /// Gets the type of wrapped request parameters from the method parameters. - /// - /// - /// - static Type GetRequestTypeFromMethod(MethodInfo methodInfo) + /// + /// Gets the type of wrapped request parameters from the method parameters. + /// + /// + /// + static Type GetRequestTypeFromMethod(MethodInfo methodInfo) + { + var parameterTypes = methodInfo.GetParameters().Select(x => x.ParameterType).ToArray(); + switch (parameterTypes.Length) { - var parameterTypes = methodInfo.GetParameters().Select(x => x.ParameterType).ToArray(); - switch (parameterTypes.Length) - { - case 0: return typeof(Nil); - case 1: return parameterTypes[0]; - case 2: return typeof(DynamicArgumentTuple<,>).MakeGenericType(parameterTypes[0], parameterTypes[1]); - case 3: return typeof(DynamicArgumentTuple<,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2]); - case 4: return typeof(DynamicArgumentTuple<,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3]); - case 5: return typeof(DynamicArgumentTuple<,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4]); - case 6: return typeof(DynamicArgumentTuple<,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5]); - case 7: return typeof(DynamicArgumentTuple<,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6]); - case 8: return typeof(DynamicArgumentTuple<,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7]); - case 9: return typeof(DynamicArgumentTuple<,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8]); - case 10: return typeof(DynamicArgumentTuple<,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9]); - case 11: return typeof(DynamicArgumentTuple<,,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9], parameterTypes[10]); - case 12: return typeof(DynamicArgumentTuple<,,,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9], parameterTypes[10], parameterTypes[11]); - case 13: return typeof(DynamicArgumentTuple<,,,,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9], parameterTypes[10], parameterTypes[11], parameterTypes[12]); - case 14: return typeof(DynamicArgumentTuple<,,,,,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9], parameterTypes[10], parameterTypes[11], parameterTypes[12], parameterTypes[13]); - case 15: return typeof(DynamicArgumentTuple<,,,,,,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9], parameterTypes[10], parameterTypes[11], parameterTypes[12], parameterTypes[13], parameterTypes[14]); - default: throw new InvalidOperationException($"A method '{methodInfo.Name}' has too many parameters."); - } + case 0: return typeof(Nil); + case 1: return parameterTypes[0]; + case 2: return typeof(DynamicArgumentTuple<,>).MakeGenericType(parameterTypes[0], parameterTypes[1]); + case 3: return typeof(DynamicArgumentTuple<,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2]); + case 4: return typeof(DynamicArgumentTuple<,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3]); + case 5: return typeof(DynamicArgumentTuple<,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4]); + case 6: return typeof(DynamicArgumentTuple<,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5]); + case 7: return typeof(DynamicArgumentTuple<,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6]); + case 8: return typeof(DynamicArgumentTuple<,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7]); + case 9: return typeof(DynamicArgumentTuple<,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8]); + case 10: return typeof(DynamicArgumentTuple<,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9]); + case 11: return typeof(DynamicArgumentTuple<,,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9], parameterTypes[10]); + case 12: return typeof(DynamicArgumentTuple<,,,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9], parameterTypes[10], parameterTypes[11]); + case 13: return typeof(DynamicArgumentTuple<,,,,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9], parameterTypes[10], parameterTypes[11], parameterTypes[12]); + case 14: return typeof(DynamicArgumentTuple<,,,,,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9], parameterTypes[10], parameterTypes[11], parameterTypes[12], parameterTypes[13]); + case 15: return typeof(DynamicArgumentTuple<,,,,,,,,,,,,,,>).MakeGenericType(parameterTypes[0], parameterTypes[1], parameterTypes[2], parameterTypes[3], parameterTypes[4], parameterTypes[5], parameterTypes[6], parameterTypes[7], parameterTypes[8], parameterTypes[9], parameterTypes[10], parameterTypes[11], parameterTypes[12], parameterTypes[13], parameterTypes[14]); + default: throw new InvalidOperationException($"A method '{methodInfo.Name}' has too many parameters."); } } } diff --git a/src/MagicOnion.Client/IMagicOnionAwareGrpcChannel.cs b/src/MagicOnion.Client/IMagicOnionAwareGrpcChannel.cs index 01cfb3171..7e7b6a803 100644 --- a/src/MagicOnion.Client/IMagicOnionAwareGrpcChannel.cs +++ b/src/MagicOnion.Client/IMagicOnionAwareGrpcChannel.cs @@ -1,36 +1,35 @@ using Grpc.Core; -namespace MagicOnion.Client +namespace MagicOnion.Client; + +public interface IMagicOnionAwareGrpcChannel { - public interface IMagicOnionAwareGrpcChannel - { - /// - /// Register the StreamingHub under the management of the channel. - /// - void ManageStreamingHubClient(Type streamingHubInterfaceType, IStreamingHubMarker streamingHub, Func disposeAsync, Task waitForDisconnect); + /// + /// Register the StreamingHub under the management of the channel. + /// + void ManageStreamingHubClient(Type streamingHubInterfaceType, IStreamingHubMarker streamingHub, Func disposeAsync, Task waitForDisconnect); - /// - /// Gets all StreamingHubs that depends on the channel. - /// - /// - IReadOnlyCollection GetAllManagedStreamingHubs(); + /// + /// Gets all StreamingHubs that depends on the channel. + /// + /// + IReadOnlyCollection GetAllManagedStreamingHubs(); - /// - /// Create a from the channel. - /// - /// - CallInvoker CreateCallInvoker(); - } + /// + /// Create a from the channel. + /// + /// + CallInvoker CreateCallInvoker(); +} - public readonly struct ManagedStreamingHubInfo - { - public Type StreamingHubType { get; } - public IStreamingHubMarker Client { get; } +public readonly struct ManagedStreamingHubInfo +{ + public Type StreamingHubType { get; } + public IStreamingHubMarker Client { get; } - public ManagedStreamingHubInfo(Type streamingHubType, IStreamingHubMarker client) - { - StreamingHubType = streamingHubType; - Client = client; - } + public ManagedStreamingHubInfo(Type streamingHubType, IStreamingHubMarker client) + { + StreamingHubType = streamingHubType; + Client = client; } } diff --git a/src/MagicOnion.Client/IMagicOnionClientLogger.cs b/src/MagicOnion.Client/IMagicOnionClientLogger.cs index 51752bda0..9a0a1b69a 100644 --- a/src/MagicOnion.Client/IMagicOnionClientLogger.cs +++ b/src/MagicOnion.Client/IMagicOnionClientLogger.cs @@ -1,31 +1,30 @@ -namespace MagicOnion.Client +namespace MagicOnion.Client; + +public interface IMagicOnionClientLogger { - public interface IMagicOnionClientLogger + void Error(Exception ex, string message); + void Information(string message); + void Debug(string message); + void Trace(string message); +} + +public sealed class NullMagicOnionClientLogger : IMagicOnionClientLogger +{ + public static IMagicOnionClientLogger Instance { get; } = new NullMagicOnionClientLogger(); + private NullMagicOnionClientLogger() {} + public void Error(Exception ex, string message) { - void Error(Exception ex, string message); - void Information(string message); - void Debug(string message); - void Trace(string message); } - public sealed class NullMagicOnionClientLogger : IMagicOnionClientLogger + public void Information(string message) { - public static IMagicOnionClientLogger Instance { get; } = new NullMagicOnionClientLogger(); - private NullMagicOnionClientLogger() {} - public void Error(Exception ex, string message) - { - } - - public void Information(string message) - { - } + } - public void Debug(string message) - { - } + public void Debug(string message) + { + } - public void Trace(string message) - { - } + public void Trace(string message) + { } } diff --git a/src/MagicOnion.Client/IStreamingHubClient.cs b/src/MagicOnion.Client/IStreamingHubClient.cs index b49402e85..8d9d5097d 100644 --- a/src/MagicOnion.Client/IStreamingHubClient.cs +++ b/src/MagicOnion.Client/IStreamingHubClient.cs @@ -1,58 +1,56 @@ -namespace MagicOnion.Client +namespace MagicOnion.Client; + +/// +/// An interface that indicates that the StreamingHub client is implemented. +/// +public interface IStreamingHubClient { /// - /// An interface that indicates that the StreamingHub client is implemented. + /// Wait for the disconnection and return the reason. /// - public interface IStreamingHubClient - { - /// - /// Wait for the disconnection and return the reason. - /// - /// - Task WaitForDisconnectAsync(); - } + /// + Task WaitForDisconnectAsync(); +} +/// +/// Provides the reason for the StreamingHub disconnection. +/// +public readonly struct DisconnectionReason +{ /// - /// Provides the reason for the StreamingHub disconnection. + /// Gets the type of StreamingHub disconnection. /// - public readonly struct DisconnectionReason - { - /// - /// Gets the type of StreamingHub disconnection. - /// - public DisconnectionType Type { get; } + public DisconnectionType Type { get; } - /// - /// Gets the exception that caused the disconnection. - /// - public Exception? Exception { get; } + /// + /// Gets the exception that caused the disconnection. + /// + public Exception? Exception { get; } - public DisconnectionReason(DisconnectionType type, Exception? exception) - { - Type = type; - Exception = exception; - } + public DisconnectionReason(DisconnectionType type, Exception? exception) + { + Type = type; + Exception = exception; } +} +/// +/// Defines the types of StreamingHub disconnection. +/// +public enum DisconnectionType +{ /// - /// Defines the types of StreamingHub disconnection. + /// Disconnected after completing successfully. /// - public enum DisconnectionType - { - /// - /// Disconnected after completing successfully. - /// - CompletedNormally = 0, + CompletedNormally = 0, - /// - /// Disconnected due to exception while reading messages. - /// - Faulted = 1, - - /// - /// Disconnected due to reaching the heartbeat timeout. - /// - TimedOut = 2, - } + /// + /// Disconnected due to exception while reading messages. + /// + Faulted = 1, + /// + /// Disconnected due to reaching the heartbeat timeout. + /// + TimedOut = 2, } diff --git a/src/MagicOnion.Client/IStreamingHubDiagnosticHandler.cs b/src/MagicOnion.Client/IStreamingHubDiagnosticHandler.cs index 91b0ad26b..e037f5748 100644 --- a/src/MagicOnion.Client/IStreamingHubDiagnosticHandler.cs +++ b/src/MagicOnion.Client/IStreamingHubDiagnosticHandler.cs @@ -1,53 +1,52 @@ -namespace MagicOnion.Client +namespace MagicOnion.Client; + +/// +/// [Preview] The interface of the handler for StreamingHub diagnostics. This API may change in the future. +/// +public interface IStreamingHubDiagnosticHandler { + public delegate ValueTask InvokeMethodDelegate(int methodId, TRequest value); + /// - /// [Preview] The interface of the handler for StreamingHub diagnostics. This API may change in the future. + /// The callback method at the beginning of a Hub method request. This API may change in the future. /// - public interface IStreamingHubDiagnosticHandler - { - public delegate ValueTask InvokeMethodDelegate(int methodId, TRequest value); - - /// - /// The callback method at the beginning of a Hub method request. This API may change in the future. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ValueTask OnMethodInvoke(THub hubInstance, int methodId, string methodName, TRequest request, bool isFireAndForget, InvokeMethodDelegate invokeMethod); + /// + /// + /// + /// + /// + /// + /// + /// + /// + ValueTask OnMethodInvoke(THub hubInstance, int methodId, string methodName, TRequest request, bool isFireAndForget, InvokeMethodDelegate invokeMethod); - /// - /// [Preview] The callback method when a method of HubReceiver is invoked. This API may change in the future. - /// - /// - /// - /// - /// - void OnBroadcastEventRaw(THub hubInstance, int methodId, ReadOnlyMemory data); + /// + /// [Preview] The callback method when a method of HubReceiver is invoked. This API may change in the future. + /// + /// + /// + /// + /// + void OnBroadcastEventRaw(THub hubInstance, int methodId, ReadOnlyMemory data); - /// - /// [Preview] The callback method when a method of HubReceiver is invoked. This API may change in the future. - /// - /// - /// - /// - /// - /// - void OnBroadcastEvent(THub hubInstance, string methodName, T value); + /// + /// [Preview] The callback method when a method of HubReceiver is invoked. This API may change in the future. + /// + /// + /// + /// + /// + /// + void OnBroadcastEvent(THub hubInstance, string methodName, T value); - /// - /// [Preview] The callback method when the return value of a hub method call is received. This API may change in the future. - /// - /// - /// - /// - /// - /// - void OnResponseEvent(THub hubInstance, string methodName, ReadOnlyMemory data); - } + /// + /// [Preview] The callback method when the return value of a hub method call is received. This API may change in the future. + /// + /// + /// + /// + /// + /// + void OnResponseEvent(THub hubInstance, string methodName, ReadOnlyMemory data); } diff --git a/src/MagicOnion.Client/Internal/InterceptInvokeHelper.cs b/src/MagicOnion.Client/Internal/InterceptInvokeHelper.cs index 24a98454d..7b8bb5a71 100644 --- a/src/MagicOnion.Client/Internal/InterceptInvokeHelper.cs +++ b/src/MagicOnion.Client/Internal/InterceptInvokeHelper.cs @@ -1,156 +1,155 @@ -namespace MagicOnion.Client.Internal +namespace MagicOnion.Client.Internal; + +internal static class InterceptInvokeHelper { - internal static class InterceptInvokeHelper + public static ValueTask InvokeWithFilter(RequestContext context) { - public static ValueTask InvokeWithFilter(RequestContext context) + switch (context.Filters.Count) { - switch (context.Filters.Count) - { - case 0: - return new ValueTask(context.RequestMethod(context)); - case 1: - return InvokeWithFilter1(context); - case 2: - return InvokeWithFilter2(context); - case 3: - return InvokeWithFilter3(context); - case 4: - return InvokeWithFilter4(context); - case 5: - return InvokeWithFilter5(context); - case 6: - return InvokeWithFilter6(context); - case 7: - return InvokeWithFilter7(context); - case 8: - return InvokeWithFilter8(context); - case 9: - return InvokeWithFilter9(context); - case 10: - return InvokeWithFilter10(context); - default: - return InvokeRecursive(-1, context); - } + case 0: + return new ValueTask(context.RequestMethod(context)); + case 1: + return InvokeWithFilter1(context); + case 2: + return InvokeWithFilter2(context); + case 3: + return InvokeWithFilter3(context); + case 4: + return InvokeWithFilter4(context); + case 5: + return InvokeWithFilter5(context); + case 6: + return InvokeWithFilter6(context); + case 7: + return InvokeWithFilter7(context); + case 8: + return InvokeWithFilter8(context); + case 9: + return InvokeWithFilter9(context); + case 10: + return InvokeWithFilter10(context); + default: + return InvokeRecursive(-1, context); } + } - static ValueTask InvokeWithFilter1(RequestContext context) - { - return context.Filters[0].SendAsync(context, - ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync())); - } + static ValueTask InvokeWithFilter1(RequestContext context) + { + return context.Filters[0].SendAsync(context, + ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync())); + } - static ValueTask InvokeWithFilter2(RequestContext context) - { - return context.Filters[0].SendAsync(context, - x1 => x1.Filters[1].SendAsync(x1, - ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync()))); - } + static ValueTask InvokeWithFilter2(RequestContext context) + { + return context.Filters[0].SendAsync(context, + x1 => x1.Filters[1].SendAsync(x1, + ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync()))); + } - static ValueTask InvokeWithFilter3(RequestContext context) - { - return context.Filters[0].SendAsync(context, - x1 => x1.Filters[1].SendAsync(x1, - x2 => x2.Filters[2].SendAsync(x2, - ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync())))); - } + static ValueTask InvokeWithFilter3(RequestContext context) + { + return context.Filters[0].SendAsync(context, + x1 => x1.Filters[1].SendAsync(x1, + x2 => x2.Filters[2].SendAsync(x2, + ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync())))); + } - static ValueTask InvokeWithFilter4(RequestContext context) - { - return context.Filters[0].SendAsync(context, - x1 => x1.Filters[1].SendAsync(x1, - x2 => x2.Filters[2].SendAsync(x2, - x3 => x3.Filters[3].SendAsync(x3, - ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync()))))); - } + static ValueTask InvokeWithFilter4(RequestContext context) + { + return context.Filters[0].SendAsync(context, + x1 => x1.Filters[1].SendAsync(x1, + x2 => x2.Filters[2].SendAsync(x2, + x3 => x3.Filters[3].SendAsync(x3, + ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync()))))); + } - static ValueTask InvokeWithFilter5(RequestContext context) - { - return context.Filters[0].SendAsync(context, - x1 => x1.Filters[1].SendAsync(x1, - x2 => x2.Filters[2].SendAsync(x2, - x3 => x3.Filters[3].SendAsync(x3, - x4 => x4.Filters[4].SendAsync(x4, - ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync())))))); - } + static ValueTask InvokeWithFilter5(RequestContext context) + { + return context.Filters[0].SendAsync(context, + x1 => x1.Filters[1].SendAsync(x1, + x2 => x2.Filters[2].SendAsync(x2, + x3 => x3.Filters[3].SendAsync(x3, + x4 => x4.Filters[4].SendAsync(x4, + ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync())))))); + } - static ValueTask InvokeWithFilter6(RequestContext context) - { - return context.Filters[0].SendAsync(context, - x1 => x1.Filters[1].SendAsync(x1, - x2 => x2.Filters[2].SendAsync(x2, - x3 => x3.Filters[3].SendAsync(x3, - x4 => x4.Filters[4].SendAsync(x4, - x5 => x5.Filters[5].SendAsync(x5, - ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync()))))))); - } + static ValueTask InvokeWithFilter6(RequestContext context) + { + return context.Filters[0].SendAsync(context, + x1 => x1.Filters[1].SendAsync(x1, + x2 => x2.Filters[2].SendAsync(x2, + x3 => x3.Filters[3].SendAsync(x3, + x4 => x4.Filters[4].SendAsync(x4, + x5 => x5.Filters[5].SendAsync(x5, + ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync()))))))); + } - static ValueTask InvokeWithFilter7(RequestContext context) - { - return context.Filters[0].SendAsync(context, - x1 => x1.Filters[1].SendAsync(x1, - x2 => x2.Filters[2].SendAsync(x2, - x3 => x3.Filters[3].SendAsync(x3, - x4 => x4.Filters[4].SendAsync(x4, - x5 => x5.Filters[5].SendAsync(x5, - x6 => x6.Filters[6].SendAsync(x6, - ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync())))))))); - } + static ValueTask InvokeWithFilter7(RequestContext context) + { + return context.Filters[0].SendAsync(context, + x1 => x1.Filters[1].SendAsync(x1, + x2 => x2.Filters[2].SendAsync(x2, + x3 => x3.Filters[3].SendAsync(x3, + x4 => x4.Filters[4].SendAsync(x4, + x5 => x5.Filters[5].SendAsync(x5, + x6 => x6.Filters[6].SendAsync(x6, + ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync())))))))); + } - static ValueTask InvokeWithFilter8(RequestContext context) - { - return context.Filters[0].SendAsync(context, - x1 => x1.Filters[1].SendAsync(x1, - x2 => x2.Filters[2].SendAsync(x2, - x3 => x3.Filters[3].SendAsync(x3, - x4 => x4.Filters[4].SendAsync(x4, - x5 => x5.Filters[5].SendAsync(x5, - x6 => x6.Filters[6].SendAsync(x6, - x7 => x7.Filters[7].SendAsync(x7, - ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync()))))))))); - } + static ValueTask InvokeWithFilter8(RequestContext context) + { + return context.Filters[0].SendAsync(context, + x1 => x1.Filters[1].SendAsync(x1, + x2 => x2.Filters[2].SendAsync(x2, + x3 => x3.Filters[3].SendAsync(x3, + x4 => x4.Filters[4].SendAsync(x4, + x5 => x5.Filters[5].SendAsync(x5, + x6 => x6.Filters[6].SendAsync(x6, + x7 => x7.Filters[7].SendAsync(x7, + ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync()))))))))); + } - static ValueTask InvokeWithFilter9(RequestContext context) - { - return context.Filters[0].SendAsync(context, - x1 => x1.Filters[1].SendAsync(x1, - x2 => x2.Filters[2].SendAsync(x2, - x3 => x3.Filters[3].SendAsync(x3, - x4 => x4.Filters[4].SendAsync(x4, - x5 => x5.Filters[5].SendAsync(x5, - x6 => x6.Filters[6].SendAsync(x6, - x7 => x7.Filters[7].SendAsync(x7, - x8 => x8.Filters[8].SendAsync(x8, - ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync())))))))))); - } + static ValueTask InvokeWithFilter9(RequestContext context) + { + return context.Filters[0].SendAsync(context, + x1 => x1.Filters[1].SendAsync(x1, + x2 => x2.Filters[2].SendAsync(x2, + x3 => x3.Filters[3].SendAsync(x3, + x4 => x4.Filters[4].SendAsync(x4, + x5 => x5.Filters[5].SendAsync(x5, + x6 => x6.Filters[6].SendAsync(x6, + x7 => x7.Filters[7].SendAsync(x7, + x8 => x8.Filters[8].SendAsync(x8, + ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync())))))))))); + } - static ValueTask InvokeWithFilter10(RequestContext context) - { - return context.Filters[0].SendAsync(context, - x1 => x1.Filters[1].SendAsync(x1, - x2 => x2.Filters[2].SendAsync(x2, - x3 => x3.Filters[3].SendAsync(x3, - x4 => x4.Filters[4].SendAsync(x4, - x5 => x5.Filters[5].SendAsync(x5, - x6 => x6.Filters[6].SendAsync(x6, - x7 => x7.Filters[7].SendAsync(x7, - x8 => x8.Filters[8].SendAsync(x8, - x9 => x9.Filters[9].SendAsync(x9, - ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync()))))))))))); - } + static ValueTask InvokeWithFilter10(RequestContext context) + { + return context.Filters[0].SendAsync(context, + x1 => x1.Filters[1].SendAsync(x1, + x2 => x2.Filters[2].SendAsync(x2, + x3 => x3.Filters[3].SendAsync(x3, + x4 => x4.Filters[4].SendAsync(x4, + x5 => x5.Filters[5].SendAsync(x5, + x6 => x6.Filters[6].SendAsync(x6, + x7 => x7.Filters[7].SendAsync(x7, + x8 => x8.Filters[8].SendAsync(x8, + x9 => x9.Filters[9].SendAsync(x9, + ctx => new ValueTask(ctx.RequestMethod(ctx).WaitResponseAsync()))))))))))); + } - // for invoke N filters(slow path). + // for invoke N filters(slow path). - static ValueTask InvokeRecursive(int index, RequestContext context) + static ValueTask InvokeRecursive(int index, RequestContext context) + { + index += 1; // start from -1 + if (index != context.Filters.Count) + { + return context.Filters[index].SendAsync(context, ctx => InvokeRecursive(index, ctx)); + } + else { - index += 1; // start from -1 - if (index != context.Filters.Count) - { - return context.Filters[index].SendAsync(context, ctx => InvokeRecursive(index, ctx)); - } - else - { - return new ValueTask(context.RequestMethod(context).WaitResponseAsync()); - } + return new ValueTask(context.RequestMethod(context).WaitResponseAsync()); } } } diff --git a/src/MagicOnion.Client/Internal/MagicOnionMethodInvoker.cs b/src/MagicOnion.Client/Internal/MagicOnionMethodInvoker.cs index 8ef8d1c84..bb009f9eb 100644 --- a/src/MagicOnion.Client/Internal/MagicOnionMethodInvoker.cs +++ b/src/MagicOnion.Client/Internal/MagicOnionMethodInvoker.cs @@ -4,176 +4,175 @@ using MessagePack; // ReSharper disable ConvertToNullCoalescingCompoundAssignment -namespace MagicOnion.Client.Internal +namespace MagicOnion.Client.Internal; + +// Pubternal API: This class is used from generated clients and is therefore `public` but internal API. +public static class RawMethodInvoker { - // Pubternal API: This class is used from generated clients and is therefore `public` but internal API. - public static class RawMethodInvoker - { - public static RawMethodInvoker Create_RefType_RefType(MethodType methodType, string serviceName, string name, IMagicOnionSerializerProvider messageSerializerProvider) - where TRequest : class - where TResponse : class - => new RawMethodInvoker(methodType, serviceName, name, messageSerializerProvider.Create(methodType, null)); + public static RawMethodInvoker Create_RefType_RefType(MethodType methodType, string serviceName, string name, IMagicOnionSerializerProvider messageSerializerProvider) + where TRequest : class + where TResponse : class + => new RawMethodInvoker(methodType, serviceName, name, messageSerializerProvider.Create(methodType, null)); + + public static RawMethodInvoker Create_RefType_ValueType(MethodType methodType, string serviceName, string name, IMagicOnionSerializerProvider messageSerializerProvider) + where TRequest : class + => new RawMethodInvoker>(methodType, serviceName, name, messageSerializerProvider.Create(methodType, null)); + + public static RawMethodInvoker Create_ValueType_RefType(MethodType methodType, string serviceName, string name, IMagicOnionSerializerProvider messageSerializerProvider) + where TResponse : class + => new RawMethodInvoker, TResponse>(methodType, serviceName, name, messageSerializerProvider.Create(methodType, null)); - public static RawMethodInvoker Create_RefType_ValueType(MethodType methodType, string serviceName, string name, IMagicOnionSerializerProvider messageSerializerProvider) - where TRequest : class - => new RawMethodInvoker>(methodType, serviceName, name, messageSerializerProvider.Create(methodType, null)); + public static RawMethodInvoker Create_ValueType_ValueType(MethodType methodType, string serviceName, string name, IMagicOnionSerializerProvider messageSerializerProvider) + => new RawMethodInvoker, Box>(methodType, serviceName, name, messageSerializerProvider.Create(methodType, null)); +} + +public abstract class RawMethodInvoker +{ + public abstract UnaryResult InvokeUnary(MagicOnionClientBase client, string path, TRequest request); + public abstract UnaryResult InvokeUnaryNonGeneric(MagicOnionClientBase client, string path, TRequest request); + public abstract Task> InvokeServerStreaming(MagicOnionClientBase client, string path, TRequest request); + public abstract Task> InvokeClientStreaming(MagicOnionClientBase client, string path); + public abstract Task> InvokeDuplexStreaming(MagicOnionClientBase client, string path); +} - public static RawMethodInvoker Create_ValueType_RefType(MethodType methodType, string serviceName, string name, IMagicOnionSerializerProvider messageSerializerProvider) - where TResponse : class - => new RawMethodInvoker, TResponse>(methodType, serviceName, name, messageSerializerProvider.Create(methodType, null)); +public sealed class RawMethodInvoker : RawMethodInvoker + where TRawRequest : class + where TRawResponse : class +{ + readonly Method method; + readonly Func createUnaryResponseContext; - public static RawMethodInvoker Create_ValueType_ValueType(MethodType methodType, string serviceName, string name, IMagicOnionSerializerProvider messageSerializerProvider) - => new RawMethodInvoker, Box>(methodType, serviceName, name, messageSerializerProvider.Create(methodType, null)); + public RawMethodInvoker(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer) + { + this.method = GrpcMethodHelper.CreateMethod(methodType, serviceName, name, messageSerializer); + this.createUnaryResponseContext = context => ResponseContext.Create( + context.Client.Options.CallInvoker.AsyncUnaryCall(method, context.Client.Options.Host, context.CallOptions, GrpcMethodHelper.ToRaw(((RequestContext)context).Request)) + ); } - public abstract class RawMethodInvoker + public override UnaryResult InvokeUnary(MagicOnionClientBase client, string path, TRequest request) { - public abstract UnaryResult InvokeUnary(MagicOnionClientBase client, string path, TRequest request); - public abstract UnaryResult InvokeUnaryNonGeneric(MagicOnionClientBase client, string path, TRequest request); - public abstract Task> InvokeServerStreaming(MagicOnionClientBase client, string path, TRequest request); - public abstract Task> InvokeClientStreaming(MagicOnionClientBase client, string path); - public abstract Task> InvokeDuplexStreaming(MagicOnionClientBase client, string path); + var future = InvokeUnaryCore(client, path, request, createUnaryResponseContext); + return new UnaryResult(future); } - public sealed class RawMethodInvoker : RawMethodInvoker - where TRawRequest : class - where TRawResponse : class + public override UnaryResult InvokeUnaryNonGeneric(MagicOnionClientBase client, string path, TRequest request) { - readonly Method method; - readonly Func createUnaryResponseContext; + var future = (Task>)(object)InvokeUnaryCore(client, path, request, createUnaryResponseContext); + return new UnaryResult(future); + } - public RawMethodInvoker(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer) + async Task> InvokeUnaryCore(MagicOnionClientBase client, string path, TRequest request, Func requestMethod) + { + var requestContext = new RequestContext(request, client, path, client.Options.CallOptions, typeof(TResponse), client.Options.Filters, requestMethod); + var response = await InterceptInvokeHelper.InvokeWithFilter(requestContext); + var result = response as IResponseContext; + if (result != null) { - this.method = GrpcMethodHelper.CreateMethod(methodType, serviceName, name, messageSerializer); - this.createUnaryResponseContext = context => ResponseContext.Create( - context.Client.Options.CallInvoker.AsyncUnaryCall(method, context.Client.Options.Host, context.CallOptions, GrpcMethodHelper.ToRaw(((RequestContext)context).Request)) - ); + return result; } - - public override UnaryResult InvokeUnary(MagicOnionClientBase client, string path, TRequest request) + else { - var future = InvokeUnaryCore(client, path, request, createUnaryResponseContext); - return new UnaryResult(future); + throw new InvalidOperationException("ResponseContext is null."); } + } - public override UnaryResult InvokeUnaryNonGeneric(MagicOnionClientBase client, string path, TRequest request) - { - var future = (Task>)(object)InvokeUnaryCore(client, path, request, createUnaryResponseContext); - return new UnaryResult(future); - } + public override Task> InvokeServerStreaming(MagicOnionClientBase client, string path, TRequest request) + => Task.FromResult( + new ServerStreamingResult( + new AsyncServerStreamingCallWrapper( + client.Options.CallInvoker.AsyncServerStreamingCall(method, client.Options.Host, client.Options.CallOptions, GrpcMethodHelper.ToRaw(request))))); + + public override Task> InvokeClientStreaming(MagicOnionClientBase client, string path) + => Task.FromResult( + new ClientStreamingResult( + new AsyncClientStreamingCallWrapper( + client.Options.CallInvoker.AsyncClientStreamingCall(method, client.Options.Host, client.Options.CallOptions)))); + + public override Task> InvokeDuplexStreaming(MagicOnionClientBase client, string path) + => Task.FromResult( + new DuplexStreamingResult( + new AsyncDuplexStreamingCallWrapper( + client.Options.CallInvoker.AsyncDuplexStreamingCall(method, client.Options.Host, client.Options.CallOptions)))); + + class AsyncServerStreamingCallWrapper : IAsyncServerStreamingCallWrapper + { + readonly AsyncServerStreamingCall inner; + + IAsyncStreamReader? responseStream; - async Task> InvokeUnaryCore(MagicOnionClientBase client, string path, TRequest request, Func requestMethod) + public AsyncServerStreamingCallWrapper(AsyncServerStreamingCall inner) { - var requestContext = new RequestContext(request, client, path, client.Options.CallOptions, typeof(TResponse), client.Options.Filters, requestMethod); - var response = await InterceptInvokeHelper.InvokeWithFilter(requestContext); - var result = response as IResponseContext; - if (result != null) - { - return result; - } - else - { - throw new InvalidOperationException("ResponseContext is null."); - } + this.inner = inner; } - public override Task> InvokeServerStreaming(MagicOnionClientBase client, string path, TRequest request) - => Task.FromResult( - new ServerStreamingResult( - new AsyncServerStreamingCallWrapper( - client.Options.CallInvoker.AsyncServerStreamingCall(method, client.Options.Host, client.Options.CallOptions, GrpcMethodHelper.ToRaw(request))))); - - public override Task> InvokeClientStreaming(MagicOnionClientBase client, string path) - => Task.FromResult( - new ClientStreamingResult( - new AsyncClientStreamingCallWrapper( - client.Options.CallInvoker.AsyncClientStreamingCall(method, client.Options.Host, client.Options.CallOptions)))); - - public override Task> InvokeDuplexStreaming(MagicOnionClientBase client, string path) - => Task.FromResult( - new DuplexStreamingResult( - new AsyncDuplexStreamingCallWrapper( - client.Options.CallInvoker.AsyncDuplexStreamingCall(method, client.Options.Host, client.Options.CallOptions)))); - - class AsyncServerStreamingCallWrapper : IAsyncServerStreamingCallWrapper + public Task ResponseHeadersAsync + => inner.ResponseHeadersAsync; + public Status GetStatus() + => inner.GetStatus(); + public Metadata GetTrailers() + => inner.GetTrailers(); + + public IAsyncStreamReader ResponseStream + => responseStream ?? (responseStream = new MagicOnionAsyncStreamReader(inner.ResponseStream)); + + public void Dispose() + => inner.Dispose(); + } + + class AsyncClientStreamingCallWrapper : IAsyncClientStreamingCallWrapper + { + readonly AsyncClientStreamingCall inner; + IClientStreamWriter? requestStream; + + public AsyncClientStreamingCallWrapper(AsyncClientStreamingCall inner) { - readonly AsyncServerStreamingCall inner; + this.inner = inner; + } - IAsyncStreamReader? responseStream; + public Task ResponseHeadersAsync + => inner.ResponseHeadersAsync; + public Status GetStatus() + => inner.GetStatus(); + public Metadata GetTrailers() + => inner.GetTrailers(); - public AsyncServerStreamingCallWrapper(AsyncServerStreamingCall inner) - { - this.inner = inner; - } + public IClientStreamWriter RequestStream + => requestStream ?? (requestStream = new MagicOnionClientStreamWriter(inner.RequestStream)); + public Task ResponseAsync + => ResponseAsyncCore(); - public Task ResponseHeadersAsync - => inner.ResponseHeadersAsync; - public Status GetStatus() - => inner.GetStatus(); - public Metadata GetTrailers() - => inner.GetTrailers(); + async Task ResponseAsyncCore() + => GrpcMethodHelper.FromRaw(await inner.ResponseAsync.ConfigureAwait(false)); - public IAsyncStreamReader ResponseStream - => responseStream ?? (responseStream = new MagicOnionAsyncStreamReader(inner.ResponseStream)); + public void Dispose() + => inner.Dispose(); + } - public void Dispose() - => inner.Dispose(); - } + class AsyncDuplexStreamingCallWrapper : IAsyncDuplexStreamingCallWrapper + { + readonly AsyncDuplexStreamingCall inner; + IClientStreamWriter? requestStream; + IAsyncStreamReader? responseStream; - class AsyncClientStreamingCallWrapper : IAsyncClientStreamingCallWrapper + public AsyncDuplexStreamingCallWrapper(AsyncDuplexStreamingCall inner) { - readonly AsyncClientStreamingCall inner; - IClientStreamWriter? requestStream; - - public AsyncClientStreamingCallWrapper(AsyncClientStreamingCall inner) - { - this.inner = inner; - } - - public Task ResponseHeadersAsync - => inner.ResponseHeadersAsync; - public Status GetStatus() - => inner.GetStatus(); - public Metadata GetTrailers() - => inner.GetTrailers(); - - public IClientStreamWriter RequestStream - => requestStream ?? (requestStream = new MagicOnionClientStreamWriter(inner.RequestStream)); - public Task ResponseAsync - => ResponseAsyncCore(); - - async Task ResponseAsyncCore() - => GrpcMethodHelper.FromRaw(await inner.ResponseAsync.ConfigureAwait(false)); - - public void Dispose() - => inner.Dispose(); + this.inner = inner; } - class AsyncDuplexStreamingCallWrapper : IAsyncDuplexStreamingCallWrapper - { - readonly AsyncDuplexStreamingCall inner; - IClientStreamWriter? requestStream; - IAsyncStreamReader? responseStream; - - public AsyncDuplexStreamingCallWrapper(AsyncDuplexStreamingCall inner) - { - this.inner = inner; - } - - public Task ResponseHeadersAsync - => inner.ResponseHeadersAsync; - public Status GetStatus() - => inner.GetStatus(); - public Metadata GetTrailers() - => inner.GetTrailers(); - - public IClientStreamWriter RequestStream - => requestStream ?? (requestStream = new MagicOnionClientStreamWriter(inner.RequestStream)); - public IAsyncStreamReader ResponseStream - => responseStream ?? (responseStream = new MagicOnionAsyncStreamReader(inner.ResponseStream)); - - public void Dispose() - => inner.Dispose(); - } + public Task ResponseHeadersAsync + => inner.ResponseHeadersAsync; + public Status GetStatus() + => inner.GetStatus(); + public Metadata GetTrailers() + => inner.GetTrailers(); + + public IClientStreamWriter RequestStream + => requestStream ?? (requestStream = new MagicOnionClientStreamWriter(inner.RequestStream)); + public IAsyncStreamReader ResponseStream + => responseStream ?? (responseStream = new MagicOnionAsyncStreamReader(inner.ResponseStream)); + + public void Dispose() + => inner.Dispose(); } } diff --git a/src/MagicOnion.Client/Internal/StreamingHubClientHeartbeatManager.cs b/src/MagicOnion.Client/Internal/StreamingHubClientHeartbeatManager.cs index 176beccbf..521dea273 100644 --- a/src/MagicOnion.Client/Internal/StreamingHubClientHeartbeatManager.cs +++ b/src/MagicOnion.Client/Internal/StreamingHubClientHeartbeatManager.cs @@ -1,218 +1,217 @@ using System.Threading.Channels; using MagicOnion.Internal; -namespace MagicOnion.Client.Internal +namespace MagicOnion.Client.Internal; + +internal class StreamingHubClientHeartbeatManager : IAsyncDisposable { - internal class StreamingHubClientHeartbeatManager : IAsyncDisposable + readonly object gate = new(); + readonly CancellationTokenSource timeoutTokenSource; + readonly CancellationTokenSource shutdownTokenSource; + readonly TimeSpan heartbeatInterval; + readonly TimeSpan timeoutPeriod; + readonly Action? onServerHeartbeatReceived; + readonly Action? onClientHeartbeatResponseReceived; + readonly SynchronizationContext? synchronizationContext; + readonly ChannelWriter writer; + readonly TimeProvider timeProvider; + readonly long timestampOrigin; + + SendOrPostCallback? processServerHeartbeatCoreCache; + SendOrPostCallback? processClientHeartbeatResponseCoreCache; + Task? heartbeatLoopTask; + short sequence; + bool isTimeoutTimerRunning; + bool disposed; + + long ElapsedMillisecondsFromOrigin => (long)timeProvider.GetElapsedTime(timestampOrigin).TotalMilliseconds; + + public CancellationToken TimeoutToken => timeoutTokenSource.Token; + + bool IsDisposed => Volatile.Read(ref disposed); + + public StreamingHubClientHeartbeatManager( + ChannelWriter writer, + TimeSpan heartbeatInterval, + TimeSpan timeoutPeriod, + Action? onServerHeartbeatReceived, + Action? onClientHeartbeatResponseReceived, + SynchronizationContext? synchronizationContext, + TimeProvider timeProvider + ) { - readonly object gate = new(); - readonly CancellationTokenSource timeoutTokenSource; - readonly CancellationTokenSource shutdownTokenSource; - readonly TimeSpan heartbeatInterval; - readonly TimeSpan timeoutPeriod; - readonly Action? onServerHeartbeatReceived; - readonly Action? onClientHeartbeatResponseReceived; - readonly SynchronizationContext? synchronizationContext; - readonly ChannelWriter writer; - readonly TimeProvider timeProvider; - readonly long timestampOrigin; - - SendOrPostCallback? processServerHeartbeatCoreCache; - SendOrPostCallback? processClientHeartbeatResponseCoreCache; - Task? heartbeatLoopTask; - short sequence; - bool isTimeoutTimerRunning; - bool disposed; - - long ElapsedMillisecondsFromOrigin => (long)timeProvider.GetElapsedTime(timestampOrigin).TotalMilliseconds; - - public CancellationToken TimeoutToken => timeoutTokenSource.Token; - - bool IsDisposed => Volatile.Read(ref disposed); - - public StreamingHubClientHeartbeatManager( - ChannelWriter writer, - TimeSpan heartbeatInterval, - TimeSpan timeoutPeriod, - Action? onServerHeartbeatReceived, - Action? onClientHeartbeatResponseReceived, - SynchronizationContext? synchronizationContext, - TimeProvider timeProvider - ) - { - timeoutTokenSource = new( + timeoutTokenSource = new( #if NET8_0_OR_GREATER Timeout.InfiniteTimeSpan, timeProvider #endif - ); - this.writer = writer; - this.heartbeatInterval = heartbeatInterval; - this.timeoutPeriod = timeoutPeriod; - this.onServerHeartbeatReceived = onServerHeartbeatReceived; - this.onClientHeartbeatResponseReceived = onClientHeartbeatResponseReceived; - this.synchronizationContext = synchronizationContext; - this.shutdownTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token); - this.timeProvider = timeProvider; - this.timestampOrigin = timeProvider.GetTimestamp(); - } + ); + this.writer = writer; + this.heartbeatInterval = heartbeatInterval; + this.timeoutPeriod = timeoutPeriod; + this.onServerHeartbeatReceived = onServerHeartbeatReceived; + this.onClientHeartbeatResponseReceived = onClientHeartbeatResponseReceived; + this.synchronizationContext = synchronizationContext; + this.shutdownTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token); + this.timeProvider = timeProvider; + this.timestampOrigin = timeProvider.GetTimestamp(); + } - public void StartClientHeartbeatLoop() - { - heartbeatLoopTask = RunClientHeartbeatLoopAsync(); - } + public void StartClientHeartbeatLoop() + { + heartbeatLoopTask = RunClientHeartbeatLoopAsync(); + } - async Task RunClientHeartbeatLoopAsync() + async Task RunClientHeartbeatLoopAsync() + { + while (!IsDisposed) { - while (!IsDisposed) - { - await Task.Delay(heartbeatInterval + await Task.Delay(heartbeatInterval #if NET8_0_OR_GREATER , timeProvider #endif - , shutdownTokenSource.Token).ConfigureAwait(false); + , shutdownTokenSource.Token).ConfigureAwait(false); - SendClientHeartbeat(); - } + SendClientHeartbeat(); } + } - void SendClientHeartbeat() + void SendClientHeartbeat() + { + lock (gate) { - lock (gate) - { - if (IsDisposed) return; - - shutdownTokenSource.Token.ThrowIfCancellationRequested(); + if (IsDisposed) return; - // Writes a ClientHeartbeat to the writer queue. - _ = writer.TryWrite(BuildClientHeartbeatMessage(sequence)); + shutdownTokenSource.Token.ThrowIfCancellationRequested(); - if (!isTimeoutTimerRunning) - { - // Start/Restart the timeout cancellation timer. - timeoutTokenSource.CancelAfter(timeoutPeriod); - isTimeoutTimerRunning = true; - } + // Writes a ClientHeartbeat to the writer queue. + _ = writer.TryWrite(BuildClientHeartbeatMessage(sequence)); - sequence++; + if (!isTimeoutTimerRunning) + { + // Start/Restart the timeout cancellation timer. + timeoutTokenSource.CancelAfter(timeoutPeriod); + isTimeoutTimerRunning = true; } + + sequence++; } + } - public void ProcessClientHeartbeatResponse(StreamingHubPayload payload) - { - if (IsDisposed) return; + public void ProcessClientHeartbeatResponse(StreamingHubPayload payload) + { + if (IsDisposed) return; - processClientHeartbeatResponseCoreCache ??= ProcessClientHeartbeatResponseCore(onClientHeartbeatResponseReceived); + processClientHeartbeatResponseCoreCache ??= ProcessClientHeartbeatResponseCore(onClientHeartbeatResponseReceived); - if (synchronizationContext is null) - { - processClientHeartbeatResponseCoreCache(payload); - } - else - { - synchronizationContext.Post(processClientHeartbeatResponseCoreCache, payload); - } + if (synchronizationContext is null) + { + processClientHeartbeatResponseCoreCache(payload); } - - public void ProcessServerHeartbeat(StreamingHubPayload payload) + else { - if (IsDisposed) return; + synchronizationContext.Post(processClientHeartbeatResponseCoreCache, payload); + } + } - processServerHeartbeatCoreCache ??= ProcessServerHeartbeatCore(onServerHeartbeatReceived); + public void ProcessServerHeartbeat(StreamingHubPayload payload) + { + if (IsDisposed) return; - if (synchronizationContext is null) - { - processServerHeartbeatCoreCache(payload); - } - else - { - synchronizationContext.Post(processServerHeartbeatCoreCache, payload); - } + processServerHeartbeatCoreCache ??= ProcessServerHeartbeatCore(onServerHeartbeatReceived); + + if (synchronizationContext is null) + { + processServerHeartbeatCoreCache(payload); + } + else + { + synchronizationContext.Post(processServerHeartbeatCoreCache, payload); } + } - SendOrPostCallback ProcessClientHeartbeatResponseCore(Action? clientHeartbeatReceivedAction) => (state) => + SendOrPostCallback ProcessClientHeartbeatResponseCore(Action? clientHeartbeatReceivedAction) => (state) => + { + lock (gate) { - lock (gate) - { - if (IsDisposed) return; + if (IsDisposed) return; - var payload = (StreamingHubPayload)state!; - var reader = new StreamingHubClientMessageReader(payload.Memory); - _ = reader.ReadMessageType(); - var (sentSequence, clientSentAtElapsedMsFromOrigin) = reader.ReadClientHeartbeatResponse(); + var payload = (StreamingHubPayload)state!; + var reader = new StreamingHubClientMessageReader(payload.Memory); + _ = reader.ReadMessageType(); + var (sentSequence, clientSentAtElapsedMsFromOrigin) = reader.ReadClientHeartbeatResponse(); - if (sentSequence == sequence - 1/* NOTE: Sequence already 1 advanced.*/) - { - // Cancel the running timeout cancellation timer. - timeoutTokenSource.CancelAfter(Timeout.InfiniteTimeSpan); - isTimeoutTimerRunning = false; - } + if (sentSequence == sequence - 1/* NOTE: Sequence already 1 advanced.*/) + { + // Cancel the running timeout cancellation timer. + timeoutTokenSource.CancelAfter(Timeout.InfiniteTimeSpan); + isTimeoutTimerRunning = false; + } - var elapsed = ElapsedMillisecondsFromOrigin - clientSentAtElapsedMsFromOrigin; + var elapsed = ElapsedMillisecondsFromOrigin - clientSentAtElapsedMsFromOrigin; - clientHeartbeatReceivedAction?.Invoke(new ClientHeartbeatEvent(elapsed)); - StreamingHubPayloadPool.Shared.Return(payload); - } - }; + clientHeartbeatReceivedAction?.Invoke(new ClientHeartbeatEvent(elapsed)); + StreamingHubPayloadPool.Shared.Return(payload); + } + }; - SendOrPostCallback ProcessServerHeartbeatCore(Action? serverHeartbeatReceivedAction) => (state) => + SendOrPostCallback ProcessServerHeartbeatCore(Action? serverHeartbeatReceivedAction) => (state) => + { + lock (gate) { - lock (gate) - { - if (IsDisposed) return; - - var payload = (StreamingHubPayload)state!; - var reader = new StreamingHubClientMessageReader(payload.Memory); - _ = reader.ReadMessageType(); - var (serverSentSequence, serverSentAt, metadata) = reader.ReadServerHeartbeat(); + if (IsDisposed) return; - serverHeartbeatReceivedAction?.Invoke(new ServerHeartbeatEvent(serverSentAt, metadata)); + var payload = (StreamingHubPayload)state!; + var reader = new StreamingHubClientMessageReader(payload.Memory); + _ = reader.ReadMessageType(); + var (serverSentSequence, serverSentAt, metadata) = reader.ReadServerHeartbeat(); - // Writes a ServerHeartbeatResponse to the writer queue. - _ = writer.TryWrite(BuildServerHeartbeatMessage(serverSentSequence, serverSentAt)); + serverHeartbeatReceivedAction?.Invoke(new ServerHeartbeatEvent(serverSentAt, metadata)); - StreamingHubPayloadPool.Shared.Return(payload); - } - }; + // Writes a ServerHeartbeatResponse to the writer queue. + _ = writer.TryWrite(BuildServerHeartbeatMessage(serverSentSequence, serverSentAt)); - StreamingHubPayload BuildServerHeartbeatMessage(short serverSequence, long serverSentAt) - { - Span buffer = stackalloc byte[32]; - StreamingHubMessageWriter.WriteServerHeartbeatMessageResponse(buffer, serverSequence, serverSentAt, out var written); - return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.Slice(0, written)); + StreamingHubPayloadPool.Shared.Return(payload); } + }; - StreamingHubPayload BuildClientHeartbeatMessage(short clientSequence) - { - Span buffer = stackalloc byte[32]; - StreamingHubMessageWriter.WriteClientHeartbeatMessage(buffer, clientSequence, ElapsedMillisecondsFromOrigin, out var written); - return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.Slice(0, written)); - } + StreamingHubPayload BuildServerHeartbeatMessage(short serverSequence, long serverSentAt) + { + Span buffer = stackalloc byte[32]; + StreamingHubMessageWriter.WriteServerHeartbeatMessageResponse(buffer, serverSequence, serverSentAt, out var written); + return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.Slice(0, written)); + } - public async ValueTask DisposeAsync() - { - Volatile.Write(ref disposed, true); - shutdownTokenSource.Cancel(); + StreamingHubPayload BuildClientHeartbeatMessage(short clientSequence) + { + Span buffer = stackalloc byte[32]; + StreamingHubMessageWriter.WriteClientHeartbeatMessage(buffer, clientSequence, ElapsedMillisecondsFromOrigin, out var written); + return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.Slice(0, written)); + } + + public async ValueTask DisposeAsync() + { + Volatile.Write(ref disposed, true); + shutdownTokenSource.Cancel(); - if (heartbeatLoopTask != null) + if (heartbeatLoopTask != null) + { + try { - try - { - await heartbeatLoopTask.ConfigureAwait(false); - } - catch - { - } + await heartbeatLoopTask.ConfigureAwait(false); } + catch + { + } + } - DisposeCore(); + DisposeCore(); - void DisposeCore() + void DisposeCore() + { + lock (gate) { - lock (gate) - { - shutdownTokenSource.Dispose(); - timeoutTokenSource.Dispose(); - } + shutdownTokenSource.Dispose(); + timeoutTokenSource.Dispose(); } } } diff --git a/src/MagicOnion.Client/Internal/StreamingHubResponseTaskSource.cs b/src/MagicOnion.Client/Internal/StreamingHubResponseTaskSource.cs index 2c12af2b9..fb49fd561 100644 --- a/src/MagicOnion.Client/Internal/StreamingHubResponseTaskSource.cs +++ b/src/MagicOnion.Client/Internal/StreamingHubResponseTaskSource.cs @@ -2,96 +2,95 @@ using System.Diagnostics; using System.Threading.Tasks.Sources; -namespace MagicOnion.Client.Internal +namespace MagicOnion.Client.Internal; + +internal class StreamingHubResponseTaskSourcePool : ObjectPool> { - internal class StreamingHubResponseTaskSourcePool : ObjectPool> + public static StreamingHubResponseTaskSourcePool Shared { get; } = new(); + + public StreamingHubResponseTaskSourcePool() + : base(static () => new StreamingHubResponseTaskSource()) + { } + + public StreamingHubResponseTaskSource RentOrCreate() { - public static StreamingHubResponseTaskSourcePool Shared { get; } = new(); + var item = RentOrCreateCore(); + item.Reset(); + return item; + } - public StreamingHubResponseTaskSourcePool() - : base(static () => new StreamingHubResponseTaskSource()) - { } + public void Return(StreamingHubResponseTaskSource item) + => ReturnCore(item); +} - public StreamingHubResponseTaskSource RentOrCreate() - { - var item = RentOrCreateCore(); - item.Reset(); - return item; - } +internal interface IStreamingHubResponseTaskSource +{ + bool TrySetException(Exception error); + bool TrySetCanceled(); +} - public void Return(StreamingHubResponseTaskSource item) - => ReturnCore(item); - } +internal class StreamingHubResponseTaskSource : IValueTaskSource, IValueTaskSource, IStreamingHubResponseTaskSource +{ + ManualResetValueTaskSourceCore core = new() + { + // NOTE: The continuations (user code) should be executed asynchronously. (Except: Unity WebGL) + // This is because the continuation may block the thread, for example, Console.ReadLine(). + // If the thread is blocked, it will no longer return to the message consuming loop. +#if !UNITY_WEBGL + RunContinuationsAsynchronously = true +#endif + }; + + public void SetResult(T result) + => core.SetResult(result); - internal interface IStreamingHubResponseTaskSource + public bool TrySetException(Exception error) { - bool TrySetException(Exception error); - bool TrySetCanceled(); + core.SetException(error); + return true; } - internal class StreamingHubResponseTaskSource : IValueTaskSource, IValueTaskSource, IStreamingHubResponseTaskSource + public bool TrySetCanceled() { - ManualResetValueTaskSourceCore core = new() - { - // NOTE: The continuations (user code) should be executed asynchronously. (Except: Unity WebGL) - // This is because the continuation may block the thread, for example, Console.ReadLine(). - // If the thread is blocked, it will no longer return to the message consuming loop. -#if !UNITY_WEBGL - RunContinuationsAsynchronously = true -#endif - }; + core.SetException(new TaskCanceledException()); + return true; + } - public void SetResult(T result) - => core.SetResult(result); + public void Reset() + => core.Reset(); - public bool TrySetException(Exception error) + public short Version + => core.Version; + + [DebuggerNonUserCode] + public T GetResult(short token) + { + try { - core.SetException(error); - return true; + return core.GetResult(token); } - - public bool TrySetCanceled() + finally { - core.SetException(new TaskCanceledException()); - return true; + StreamingHubResponseTaskSourcePool.Shared.Return(this); } + } - public void Reset() - => core.Reset(); - - public short Version - => core.Version; - - [DebuggerNonUserCode] - public T GetResult(short token) + void IValueTaskSource.GetResult(short token) + { + try { - try - { - return core.GetResult(token); - } - finally - { - StreamingHubResponseTaskSourcePool.Shared.Return(this); - } + core.GetResult(token); } - - void IValueTaskSource.GetResult(short token) + finally { - try - { - core.GetResult(token); - } - finally - { - StreamingHubResponseTaskSourcePool.Shared.Return(this); - } + StreamingHubResponseTaskSourcePool.Shared.Return(this); } + } - public ValueTaskSourceStatus GetStatus(short token) - => core.GetStatus(token); + public ValueTaskSourceStatus GetStatus(short token) + => core.GetStatus(token); - public void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) - => core.OnCompleted(continuation, state, token, flags); + public void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) + => core.OnCompleted(continuation, state, token, flags); - } } diff --git a/src/MagicOnion.Client/MagicOnionClient.cs b/src/MagicOnion.Client/MagicOnionClient.cs index f0a524dd1..ecda0a95e 100644 --- a/src/MagicOnion.Client/MagicOnionClient.cs +++ b/src/MagicOnion.Client/MagicOnionClient.cs @@ -1,63 +1,62 @@ using Grpc.Core; using MagicOnion.Serialization; -namespace MagicOnion.Client -{ - public static partial class MagicOnionClient - { - static readonly IClientFilter[] EmptyFilters = Array.Empty(); +namespace MagicOnion.Client; - public static T Create(ChannelBase channel) where T : IService - => Create(channel.CreateCallInvoker(), MagicOnionSerializerProvider.Default, EmptyFilters, MagicOnionClientFactoryProvider.Default); +public static partial class MagicOnionClient +{ + static readonly IClientFilter[] EmptyFilters = Array.Empty(); - public static T Create(ChannelBase channel, IClientFilter[] clientFilters) where T : IService - => Create(channel.CreateCallInvoker(), MagicOnionSerializerProvider.Default, clientFilters, MagicOnionClientFactoryProvider.Default); + public static T Create(ChannelBase channel) where T : IService + => Create(channel.CreateCallInvoker(), MagicOnionSerializerProvider.Default, EmptyFilters, MagicOnionClientFactoryProvider.Default); - public static T Create(ChannelBase channel, IMagicOnionSerializerProvider serializerProvider) where T : IService - => Create(channel.CreateCallInvoker(), serializerProvider, Array.Empty(), MagicOnionClientFactoryProvider.Default); + public static T Create(ChannelBase channel, IClientFilter[] clientFilters) where T : IService + => Create(channel.CreateCallInvoker(), MagicOnionSerializerProvider.Default, clientFilters, MagicOnionClientFactoryProvider.Default); - public static T Create(ChannelBase channel, IMagicOnionSerializerProvider serializerProvider, IClientFilter[] clientFilters) where T : IService - => Create(channel.CreateCallInvoker(), serializerProvider, clientFilters, MagicOnionClientFactoryProvider.Default); + public static T Create(ChannelBase channel, IMagicOnionSerializerProvider serializerProvider) where T : IService + => Create(channel.CreateCallInvoker(), serializerProvider, Array.Empty(), MagicOnionClientFactoryProvider.Default); - public static T Create(ChannelBase channel, IMagicOnionSerializerProvider serializerProvider, IClientFilter[] clientFilters, IMagicOnionClientFactoryProvider clientFactoryProvider) where T : IService - => Create(channel.CreateCallInvoker(), serializerProvider, clientFilters, clientFactoryProvider); + public static T Create(ChannelBase channel, IMagicOnionSerializerProvider serializerProvider, IClientFilter[] clientFilters) where T : IService + => Create(channel.CreateCallInvoker(), serializerProvider, clientFilters, MagicOnionClientFactoryProvider.Default); - public static T Create(CallInvoker invoker) where T : IService - => Create(invoker, MagicOnionSerializerProvider.Default, EmptyFilters, MagicOnionClientFactoryProvider.Default); + public static T Create(ChannelBase channel, IMagicOnionSerializerProvider serializerProvider, IClientFilter[] clientFilters, IMagicOnionClientFactoryProvider clientFactoryProvider) where T : IService + => Create(channel.CreateCallInvoker(), serializerProvider, clientFilters, clientFactoryProvider); - public static T Create(CallInvoker invoker, IClientFilter[] clientFilters) where T : IService - => Create(invoker, MagicOnionSerializerProvider.Default, clientFilters, MagicOnionClientFactoryProvider.Default); + public static T Create(CallInvoker invoker) where T : IService + => Create(invoker, MagicOnionSerializerProvider.Default, EmptyFilters, MagicOnionClientFactoryProvider.Default); - public static T Create(CallInvoker invoker, IMagicOnionSerializerProvider serializerProvider) where T : IService - => Create(invoker, serializerProvider, EmptyFilters, MagicOnionClientFactoryProvider.Default); + public static T Create(CallInvoker invoker, IClientFilter[] clientFilters) where T : IService + => Create(invoker, MagicOnionSerializerProvider.Default, clientFilters, MagicOnionClientFactoryProvider.Default); - public static T Create(CallInvoker invoker, IMagicOnionSerializerProvider serializerProvider, IClientFilter[] clientFilters) where T : IService - => Create(invoker, serializerProvider, clientFilters, MagicOnionClientFactoryProvider.Default); + public static T Create(CallInvoker invoker, IMagicOnionSerializerProvider serializerProvider) where T : IService + => Create(invoker, serializerProvider, EmptyFilters, MagicOnionClientFactoryProvider.Default); - public static T Create(CallInvoker invoker, IMagicOnionSerializerProvider serializerProvider, IClientFilter[] clientFilters, IMagicOnionClientFactoryProvider clientFactoryProvider) - where T : IService - { - if (invoker == null) throw new ArgumentNullException(nameof(invoker)); + public static T Create(CallInvoker invoker, IMagicOnionSerializerProvider serializerProvider, IClientFilter[] clientFilters) where T : IService + => Create(invoker, serializerProvider, clientFilters, MagicOnionClientFactoryProvider.Default); - var clientOptions = new MagicOnionClientOptions(invoker, default, default, clientFilters); - return Create(clientOptions, serializerProvider, clientFactoryProvider); - } + public static T Create(CallInvoker invoker, IMagicOnionSerializerProvider serializerProvider, IClientFilter[] clientFilters, IMagicOnionClientFactoryProvider clientFactoryProvider) + where T : IService + { + if (invoker == null) throw new ArgumentNullException(nameof(invoker)); - public static T Create(MagicOnionClientOptions clientOptions, IMagicOnionSerializerProvider serializerProvider) where T : IService - => Create(clientOptions, serializerProvider, MagicOnionClientFactoryProvider.Default); + var clientOptions = new MagicOnionClientOptions(invoker, default, default, clientFilters); + return Create(clientOptions, serializerProvider, clientFactoryProvider); + } - public static T Create(MagicOnionClientOptions clientOptions, IMagicOnionSerializerProvider serializerProvider, IMagicOnionClientFactoryProvider clientFactoryProvider) - where T : IService - { - if (serializerProvider is null) throw new ArgumentNullException(nameof(serializerProvider)); - if (clientFactoryProvider is null) throw new ArgumentNullException(nameof(clientFactoryProvider)); + public static T Create(MagicOnionClientOptions clientOptions, IMagicOnionSerializerProvider serializerProvider) where T : IService + => Create(clientOptions, serializerProvider, MagicOnionClientFactoryProvider.Default); - if (!clientFactoryProvider.TryGetFactory(out var factory)) - { - throw new NotSupportedException($"Unable to get client factory for service type '{typeof(T).FullName}'."); - } + public static T Create(MagicOnionClientOptions clientOptions, IMagicOnionSerializerProvider serializerProvider, IMagicOnionClientFactoryProvider clientFactoryProvider) + where T : IService + { + if (serializerProvider is null) throw new ArgumentNullException(nameof(serializerProvider)); + if (clientFactoryProvider is null) throw new ArgumentNullException(nameof(clientFactoryProvider)); - return factory(clientOptions, serializerProvider); + if (!clientFactoryProvider.TryGetFactory(out var factory)) + { + throw new NotSupportedException($"Unable to get client factory for service type '{typeof(T).FullName}'."); } + + return factory(clientOptions, serializerProvider); } } diff --git a/src/MagicOnion.Client/MagicOnionClientBase.cs b/src/MagicOnion.Client/MagicOnionClientBase.cs index 1756171e6..e4bd5d403 100644 --- a/src/MagicOnion.Client/MagicOnionClientBase.cs +++ b/src/MagicOnion.Client/MagicOnionClientBase.cs @@ -1,69 +1,68 @@ using Grpc.Core; -namespace MagicOnion.Client +namespace MagicOnion.Client; + +public class MagicOnionClientOptions { - public class MagicOnionClientOptions + public string? Host { get; } + public CallInvoker CallInvoker { get; } + public IReadOnlyList Filters { get; } + public CallOptions CallOptions { get; } + + public MagicOnionClientOptions(CallInvoker callInvoker, string? host, CallOptions callOptions, IReadOnlyList? filters) { - public string? Host { get; } - public CallInvoker CallInvoker { get; } - public IReadOnlyList Filters { get; } - public CallOptions CallOptions { get; } + Host = host; + CallOptions = callOptions; + CallInvoker = callInvoker ?? throw new ArgumentNullException(nameof(callInvoker)); + Filters = filters ?? Array.Empty(); + } - public MagicOnionClientOptions(CallInvoker callInvoker, string? host, CallOptions callOptions, IReadOnlyList? filters) - { - Host = host; - CallOptions = callOptions; - CallInvoker = callInvoker ?? throw new ArgumentNullException(nameof(callInvoker)); - Filters = filters ?? Array.Empty(); - } + public MagicOnionClientOptions WithCallOptions(CallOptions callOptions) + => new (CallInvoker, Host, callOptions, Filters); + public MagicOnionClientOptions WithHost(string? host) + => new (CallInvoker, host, CallOptions, Filters); + public MagicOnionClientOptions WithFilters(IReadOnlyList filters) + => new (CallInvoker, Host, CallOptions, filters); +} - public MagicOnionClientOptions WithCallOptions(CallOptions callOptions) - => new (CallInvoker, Host, callOptions, Filters); - public MagicOnionClientOptions WithHost(string? host) - => new (CallInvoker, host, CallOptions, Filters); - public MagicOnionClientOptions WithFilters(IReadOnlyList filters) - => new (CallInvoker, Host, CallOptions, filters); - } +public class MagicOnionClientBase +{ + protected internal MagicOnionClientOptions Options { get; } - public class MagicOnionClientBase + protected MagicOnionClientBase(MagicOnionClientOptions options) { - protected internal MagicOnionClientOptions Options { get; } - - protected MagicOnionClientBase(MagicOnionClientOptions options) + if (options.CallOptions.Headers == null && options.Filters.Count != 0) { - if (options.CallOptions.Headers == null && options.Filters.Count != 0) - { - // always creating new Metadata is bad manner for performance - options = options.WithCallOptions(options.CallOptions.WithHeaders(new Metadata())); - } - - Options = options; + // always creating new Metadata is bad manner for performance + options = options.WithCallOptions(options.CallOptions.WithHeaders(new Metadata())); } + + Options = options; } +} - public abstract class MagicOnionClientBase : MagicOnionClientBase - where T : IService +public abstract class MagicOnionClientBase : MagicOnionClientBase + where T : IService +{ + protected MagicOnionClientBase(MagicOnionClientOptions options) + : base(options) { - protected MagicOnionClientBase(MagicOnionClientOptions options) - : base(options) - { - } + } - protected abstract MagicOnionClientBase Clone(MagicOnionClientOptions options); + protected abstract MagicOnionClientBase Clone(MagicOnionClientOptions options); - public virtual T WithCancellationToken(CancellationToken cancellationToken) - => WithOptions(Options.CallOptions.WithCancellationToken(cancellationToken)); + public virtual T WithCancellationToken(CancellationToken cancellationToken) + => WithOptions(Options.CallOptions.WithCancellationToken(cancellationToken)); - public virtual T WithDeadline(DateTime deadline) - => WithOptions(Options.CallOptions.WithDeadline(deadline)); + public virtual T WithDeadline(DateTime deadline) + => WithOptions(Options.CallOptions.WithDeadline(deadline)); - public virtual T WithHeaders(Metadata headers) - => WithOptions(Options.CallOptions.WithHeaders(headers)); + public virtual T WithHeaders(Metadata headers) + => WithOptions(Options.CallOptions.WithHeaders(headers)); - public virtual T WithHost(string host) - => (T)(object)Clone(Options.WithHost(host)); + public virtual T WithHost(string host) + => (T)(object)Clone(Options.WithHost(host)); - public virtual T WithOptions(CallOptions options) - => (T)(object)Clone(Options.WithCallOptions(options)); - } + public virtual T WithOptions(CallOptions options) + => (T)(object)Clone(Options.WithCallOptions(options)); } diff --git a/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs b/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs index 88331d7e8..deb3a386a 100644 --- a/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs +++ b/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs @@ -2,69 +2,68 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -namespace MagicOnion.Client +namespace MagicOnion.Client; + +/// +/// Provides to get a MagicOnionClient factory of the specified service type. +/// +[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "ClientFactoryProvider is resolved at runtime.")] +public static class MagicOnionClientFactoryProvider { /// - /// Provides to get a MagicOnionClient factory of the specified service type. + /// Gets or set the MagicOnionClient factory provider to use by default. /// - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "ClientFactoryProvider is resolved at runtime.")] - public static class MagicOnionClientFactoryProvider - { - /// - /// Gets or set the MagicOnionClient factory provider to use by default. - /// - public static IMagicOnionClientFactoryProvider Default { get; set; } + public static IMagicOnionClientFactoryProvider Default { get; set; } #if NETSTANDARD2_0 = DynamicClient.DynamicMagicOnionClientFactoryProvider.Instance; #else - = RuntimeFeature.IsDynamicCodeSupported - ? DynamicClient.DynamicMagicOnionClientFactoryProvider.Instance - : DynamicClient.DynamicNotSupportedMagicOnionClientFactoryProvider.Instance; + = RuntimeFeature.IsDynamicCodeSupported + ? DynamicClient.DynamicMagicOnionClientFactoryProvider.Instance + : DynamicClient.DynamicNotSupportedMagicOnionClientFactoryProvider.Instance; #endif - } +} - public delegate T MagicOnionClientFactoryDelegate(MagicOnionClientOptions clientOptions, IMagicOnionSerializerProvider serializerProvider) where T : IService; +public delegate T MagicOnionClientFactoryDelegate(MagicOnionClientOptions clientOptions, IMagicOnionSerializerProvider serializerProvider) where T : IService; +/// +/// Provides to get a MagicOnionClient factory of the specified service type. +/// +public interface IMagicOnionClientFactoryProvider +{ /// - /// Provides to get a MagicOnionClient factory of the specified service type. + /// Gets the MagicOnionClient factory of the specified service type. A return value indicates whether a factory was found or not. /// - public interface IMagicOnionClientFactoryProvider - { - /// - /// Gets the MagicOnionClient factory of the specified service type. A return value indicates whether a factory was found or not. - /// - /// A MagicOnion service interface type. - /// A MagicOnionClient factory of specified service type. - /// The value indicates whether a factory was found or not. - bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDelegate? factory) where T : IService; - } + /// A MagicOnion service interface type. + /// A MagicOnionClient factory of specified service type. + /// The value indicates whether a factory was found or not. + bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDelegate? factory) where T : IService; +} - public class ImmutableMagicOnionClientFactoryProvider : IMagicOnionClientFactoryProvider - { - readonly IMagicOnionClientFactoryProvider[] providers; +public class ImmutableMagicOnionClientFactoryProvider : IMagicOnionClientFactoryProvider +{ + readonly IMagicOnionClientFactoryProvider[] providers; - public ImmutableMagicOnionClientFactoryProvider(params IMagicOnionClientFactoryProvider[] providers) - { - this.providers = providers; - } + public ImmutableMagicOnionClientFactoryProvider(params IMagicOnionClientFactoryProvider[] providers) + { + this.providers = providers; + } - public ImmutableMagicOnionClientFactoryProvider Add(IMagicOnionClientFactoryProvider provider) - { - return new ImmutableMagicOnionClientFactoryProvider(providers.Append(provider).ToArray()); - } + public ImmutableMagicOnionClientFactoryProvider Add(IMagicOnionClientFactoryProvider provider) + { + return new ImmutableMagicOnionClientFactoryProvider(providers.Append(provider).ToArray()); + } - public bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDelegate? factory) where T : IService + public bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDelegate? factory) where T : IService + { + foreach (var provider in providers) { - foreach (var provider in providers) + if (provider.TryGetFactory(out factory)) { - if (provider.TryGetFactory(out factory)) - { - return true; - } + return true; } - - factory = default; - return false; } + + factory = default; + return false; } } diff --git a/src/MagicOnion.Client/MagicOnionClientGenerationAttribute.cs b/src/MagicOnion.Client/MagicOnionClientGenerationAttribute.cs index 8c36c93e3..4f08cfcd6 100644 --- a/src/MagicOnion.Client/MagicOnionClientGenerationAttribute.cs +++ b/src/MagicOnion.Client/MagicOnionClientGenerationAttribute.cs @@ -1,47 +1,46 @@ -namespace MagicOnion.Client +namespace MagicOnion.Client; + +/// +/// Marker attribute for generating clients of MagicOnion. +/// The source generator collects the classes specified by this attribute and uses them to generate source. +/// +[AttributeUsage(global::System.AttributeTargets.Class, AllowMultiple = false)] +public class MagicOnionClientGenerationAttribute : Attribute { /// - /// Marker attribute for generating clients of MagicOnion. - /// The source generator collects the classes specified by this attribute and uses them to generate source. + /// Gets or sets whether to disable automatically calling `Register` during start-up. (Automatic registration requires .NET 5+ or Unity) + /// + public bool DisableAutoRegistration { get; set; } + + /// + /// Gets or set the serializer used for message serialization. The default value is . + /// + public GenerateSerializerType Serializer { get; set; } = GenerateSerializerType.MessagePack; + + /// + /// Gets or set the namespace of pre-generated MessagePackFormatters. The default value is MessagePack.Formatters. + /// + public string MessagePackFormatterNamespace { get; set; } = "MessagePack.Formatters"; + + /// + /// Gets or set whether to enable the StreamingHandler diagnostic handler. This is for debugging purpose. The default value is . /// - [AttributeUsage(global::System.AttributeTargets.Class, AllowMultiple = false)] - public class MagicOnionClientGenerationAttribute : Attribute + public bool EnableStreamingHubDiagnosticHandler { get; set; } = false; + + public string GenerateFileHintNamePrefix { get; set; } = string.Empty; + + public Type[] TypesContainedInTargetAssembly { get; } + + /// Types contained in the scan target assembly + public MagicOnionClientGenerationAttribute(params Type[] typesContainedInTargetAssembly) + { + TypesContainedInTargetAssembly = typesContainedInTargetAssembly; + } + + // This enum must be mirror of `SerializerType` (MagicOnionClientSourceGenerator) + public enum GenerateSerializerType { - /// - /// Gets or sets whether to disable automatically calling `Register` during start-up. (Automatic registration requires .NET 5+ or Unity) - /// - public bool DisableAutoRegistration { get; set; } - - /// - /// Gets or set the serializer used for message serialization. The default value is . - /// - public GenerateSerializerType Serializer { get; set; } = GenerateSerializerType.MessagePack; - - /// - /// Gets or set the namespace of pre-generated MessagePackFormatters. The default value is MessagePack.Formatters. - /// - public string MessagePackFormatterNamespace { get; set; } = "MessagePack.Formatters"; - - /// - /// Gets or set whether to enable the StreamingHandler diagnostic handler. This is for debugging purpose. The default value is . - /// - public bool EnableStreamingHubDiagnosticHandler { get; set; } = false; - - public string GenerateFileHintNamePrefix { get; set; } = string.Empty; - - public Type[] TypesContainedInTargetAssembly { get; } - - /// Types contained in the scan target assembly - public MagicOnionClientGenerationAttribute(params Type[] typesContainedInTargetAssembly) - { - TypesContainedInTargetAssembly = typesContainedInTargetAssembly; - } - - // This enum must be mirror of `SerializerType` (MagicOnionClientSourceGenerator) - public enum GenerateSerializerType - { - MessagePack = 0, - MemoryPack = 1, - } + MessagePack = 0, + MemoryPack = 1, } } diff --git a/src/MagicOnion.Client/RequestContext.cs b/src/MagicOnion.Client/RequestContext.cs index a10905506..f3ea2b8e1 100644 --- a/src/MagicOnion.Client/RequestContext.cs +++ b/src/MagicOnion.Client/RequestContext.cs @@ -1,44 +1,43 @@ using Grpc.Core; -namespace MagicOnion.Client +namespace MagicOnion.Client; + +public class RequestContext : RequestContext { - public class RequestContext : RequestContext + public T Request { get; } + public override Type RequestType => typeof(T); + + public RequestContext(T request, MagicOnionClientBase client, string methodPath, CallOptions callOptions, Type responseType, IReadOnlyList filters, Func requestMethod) + : base(client, methodPath, callOptions, responseType, filters, requestMethod) { - public T Request { get; } - public override Type RequestType => typeof(T); - - public RequestContext(T request, MagicOnionClientBase client, string methodPath, CallOptions callOptions, Type responseType, IReadOnlyList filters, Func requestMethod) - : base(client, methodPath, callOptions, responseType, filters, requestMethod) - { - this.Request = request; - } + this.Request = request; } +} + +public abstract class RequestContext +{ + Dictionary? items; + + public string MethodPath { get; } + public CallOptions CallOptions { get; } + public Type ResponseType { get; } + public abstract Type RequestType { get; } + + public IDictionary Items + => items ?? (items = new Dictionary()); + + // internal use to avoid lambda capture. + internal MagicOnionClientBase Client { get; } + internal IReadOnlyList Filters { get; } + internal Func RequestMethod { get; } - public abstract class RequestContext + internal RequestContext(MagicOnionClientBase client, string methodPath, CallOptions callOptions, Type responseType, IReadOnlyList filters, Func requestMethod) { - Dictionary? items; - - public string MethodPath { get; } - public CallOptions CallOptions { get; } - public Type ResponseType { get; } - public abstract Type RequestType { get; } - - public IDictionary Items - => items ?? (items = new Dictionary()); - - // internal use to avoid lambda capture. - internal MagicOnionClientBase Client { get; } - internal IReadOnlyList Filters { get; } - internal Func RequestMethod { get; } - - internal RequestContext(MagicOnionClientBase client, string methodPath, CallOptions callOptions, Type responseType, IReadOnlyList filters, Func requestMethod) - { - this.Client = client; - this.MethodPath = methodPath; - this.CallOptions = callOptions; - this.ResponseType = responseType; - this.Filters = filters; - this.RequestMethod = requestMethod; - } + this.Client = client; + this.MethodPath = methodPath; + this.CallOptions = callOptions; + this.ResponseType = responseType; + this.Filters = filters; + this.RequestMethod = requestMethod; } } diff --git a/src/MagicOnion.Client/ResponseContext.cs b/src/MagicOnion.Client/ResponseContext.cs index fe640c972..9137096ed 100644 --- a/src/MagicOnion.Client/ResponseContext.cs +++ b/src/MagicOnion.Client/ResponseContext.cs @@ -1,118 +1,117 @@ using Grpc.Core; using MagicOnion.Internal; -namespace MagicOnion.Client +namespace MagicOnion.Client; + +internal class ResponseContextRaw : ResponseContext { - internal class ResponseContextRaw : ResponseContext - { - readonly AsyncUnaryCall? inner; + readonly AsyncUnaryCall? inner; - readonly bool hasValue; - readonly T? value; + readonly bool hasValue; + readonly T? value; - readonly bool hasMetadataAndStatus; - readonly Status status; - readonly Metadata? responseHeaders; - readonly Metadata? trailers; + readonly bool hasMetadataAndStatus; + readonly Status status; + readonly Metadata? responseHeaders; + readonly Metadata? trailers; - public ResponseContextRaw(T value, Status status, Metadata responseHeaders, Metadata trailers) - : this(null, hasValue: true, value, hasMetadataAndStatus: true, status, responseHeaders: responseHeaders, trailers: trailers) - { } + public ResponseContextRaw(T value, Status status, Metadata responseHeaders, Metadata trailers) + : this(null, hasValue: true, value, hasMetadataAndStatus: true, status, responseHeaders: responseHeaders, trailers: trailers) + { } - public ResponseContextRaw(AsyncUnaryCall inner) - : this(inner, hasValue: false, default, hasMetadataAndStatus: false, default, default, default) - { } + public ResponseContextRaw(AsyncUnaryCall inner) + : this(inner, hasValue: false, default, hasMetadataAndStatus: false, default, default, default) + { } - public ResponseContextRaw(AsyncUnaryCall? inner, bool hasValue, T? value, bool hasMetadataAndStatus, Status status, Metadata? responseHeaders, Metadata? trailers) - { - if (!hasValue && inner == null) throw new ArgumentNullException(nameof(inner)); - if (hasMetadataAndStatus && responseHeaders == null) throw new ArgumentNullException(nameof(responseHeaders)); - if (hasMetadataAndStatus && trailers == null) throw new ArgumentNullException(nameof(trailers)); + public ResponseContextRaw(AsyncUnaryCall? inner, bool hasValue, T? value, bool hasMetadataAndStatus, Status status, Metadata? responseHeaders, Metadata? trailers) + { + if (!hasValue && inner == null) throw new ArgumentNullException(nameof(inner)); + if (hasMetadataAndStatus && responseHeaders == null) throw new ArgumentNullException(nameof(responseHeaders)); + if (hasMetadataAndStatus && trailers == null) throw new ArgumentNullException(nameof(trailers)); - this.inner = inner; + this.inner = inner; - this.hasValue = hasValue; - this.value = value; + this.hasValue = hasValue; + this.value = value; - this.hasMetadataAndStatus = hasMetadataAndStatus; - this.status = status; - this.responseHeaders = responseHeaders; - this.trailers = trailers; - } + this.hasMetadataAndStatus = hasMetadataAndStatus; + this.status = status; + this.responseHeaders = responseHeaders; + this.trailers = trailers; + } - AsyncUnaryCall GetRequiredInner() - => inner ?? throw new InvalidOperationException("ResponseContextRaw has no inner AsyncUnaryCall."); + AsyncUnaryCall GetRequiredInner() + => inner ?? throw new InvalidOperationException("ResponseContextRaw has no inner AsyncUnaryCall."); - public override Type ResponseType => typeof(T); + public override Type ResponseType => typeof(T); - public override async Task WaitResponseAsync() - { - await ResponseAsync.ConfigureAwait(false); - return this; - } + public override async Task WaitResponseAsync() + { + await ResponseAsync.ConfigureAwait(false); + return this; + } - public override Status GetStatus() - => hasMetadataAndStatus - ? status - : GetRequiredInner().GetStatus(); + public override Status GetStatus() + => hasMetadataAndStatus + ? status + : GetRequiredInner().GetStatus(); - public override Task ResponseHeadersAsync - => hasMetadataAndStatus - ? Task.FromResult(responseHeaders!) - : GetRequiredInner().ResponseHeadersAsync; - public override Metadata GetTrailers() - => hasMetadataAndStatus - ? trailers! - : GetRequiredInner().GetTrailers(); - - public override Task ResponseAsync - => hasValue - ? Task.FromResult(value!) - : FromRawResponseToResponseAsync(); - - async Task FromRawResponseToResponseAsync() - => GrpcMethodHelper.FromRaw(await GetRequiredInner().ResponseAsync.ConfigureAwait(false)); + public override Task ResponseHeadersAsync + => hasMetadataAndStatus + ? Task.FromResult(responseHeaders!) + : GetRequiredInner().ResponseHeadersAsync; + public override Metadata GetTrailers() + => hasMetadataAndStatus + ? trailers! + : GetRequiredInner().GetTrailers(); + + public override Task ResponseAsync + => hasValue + ? Task.FromResult(value!) + : FromRawResponseToResponseAsync(); + + async Task FromRawResponseToResponseAsync() + => GrpcMethodHelper.FromRaw(await GetRequiredInner().ResponseAsync.ConfigureAwait(false)); - public override void Dispose() - => inner?.Dispose(); + public override void Dispose() + => inner?.Dispose(); - public override ResponseContext WithNewResult(T newValue) - => new ResponseContextRaw(inner, hasValue: true, newValue, hasMetadataAndStatus, status, responseHeaders, trailers); - } + public override ResponseContext WithNewResult(T newValue) + => new ResponseContextRaw(inner, hasValue: true, newValue, hasMetadataAndStatus, status, responseHeaders, trailers); +} - public abstract class ResponseContext : ResponseContext, IResponseContext - { - public static ResponseContext Create(AsyncUnaryCall inner) - => new ResponseContextRaw(inner); +public abstract class ResponseContext : ResponseContext, IResponseContext +{ + public static ResponseContext Create(AsyncUnaryCall inner) + => new ResponseContextRaw(inner); + + public static ResponseContext Create(T value, Status status, Metadata responseHeaders, Metadata trailers) + => new ResponseContextRaw(null, hasValue: true, value, hasMetadataAndStatus: true, status, responseHeaders: responseHeaders, trailers: trailers); + + public abstract Task ResponseAsync { get; } + public abstract ResponseContext WithNewResult(T newValue); +} - public static ResponseContext Create(T value, Status status, Metadata responseHeaders, Metadata trailers) - => new ResponseContextRaw(null, hasValue: true, value, hasMetadataAndStatus: true, status, responseHeaders: responseHeaders, trailers: trailers); +public abstract class ResponseContext : IResponseContext +{ + public abstract Task ResponseHeadersAsync { get; } + public abstract Status GetStatus(); + public abstract Metadata GetTrailers(); + public abstract void Dispose(); + public abstract Type ResponseType { get; } + + public abstract Task WaitResponseAsync(); - public abstract Task ResponseAsync { get; } - public abstract ResponseContext WithNewResult(T newValue); + public ResponseContext As() + { + return (ResponseContext)this; } - public abstract class ResponseContext : IResponseContext + public Task GetResponseAs() { - public abstract Task ResponseHeadersAsync { get; } - public abstract Status GetStatus(); - public abstract Metadata GetTrailers(); - public abstract void Dispose(); - public abstract Type ResponseType { get; } - - public abstract Task WaitResponseAsync(); - - public ResponseContext As() - { - return (ResponseContext)this; - } - - public Task GetResponseAs() - { - var t = this as ResponseContext; - if (t == null) return Task.FromResult(default(T)!); - - return t.ResponseAsync; - } + var t = this as ResponseContext; + if (t == null) return Task.FromResult(default(T)!); + + return t.ResponseAsync; } } diff --git a/src/MagicOnion.Client/ServerHeartbeatEvent.cs b/src/MagicOnion.Client/ServerHeartbeatEvent.cs index 03ddee42e..bed0acf5b 100644 --- a/src/MagicOnion.Client/ServerHeartbeatEvent.cs +++ b/src/MagicOnion.Client/ServerHeartbeatEvent.cs @@ -1,24 +1,23 @@ -namespace MagicOnion.Client +namespace MagicOnion.Client; + +/// +/// Represents a server heartbeat received event. +/// +public readonly struct ServerHeartbeatEvent { /// - /// Represents a server heartbeat received event. + /// Gets the server time at when the heartbeat was sent. /// - public readonly struct ServerHeartbeatEvent - { - /// - /// Gets the server time at when the heartbeat was sent. - /// - public DateTimeOffset ServerTime { get; } + public DateTimeOffset ServerTime { get; } - /// - /// Gets the metadata data. The data is only available during event processing. - /// - public ReadOnlyMemory Metadata { get; } + /// + /// Gets the metadata data. The data is only available during event processing. + /// + public ReadOnlyMemory Metadata { get; } - public ServerHeartbeatEvent(long serverTimeUnixMs, ReadOnlyMemory metadata) - { - ServerTime = DateTimeOffset.FromUnixTimeMilliseconds(serverTimeUnixMs); - Metadata = metadata; - } + public ServerHeartbeatEvent(long serverTimeUnixMs, ReadOnlyMemory metadata) + { + ServerTime = DateTimeOffset.FromUnixTimeMilliseconds(serverTimeUnixMs); + Metadata = metadata; } } diff --git a/src/MagicOnion.Client/StreamingHubClient.cs b/src/MagicOnion.Client/StreamingHubClient.cs index 0f6c51b56..59146e647 100644 --- a/src/MagicOnion.Client/StreamingHubClient.cs +++ b/src/MagicOnion.Client/StreamingHubClient.cs @@ -1,93 +1,92 @@ using Grpc.Core; using MagicOnion.Serialization; -namespace MagicOnion.Client +namespace MagicOnion.Client; + +public static partial class StreamingHubClient { - public static partial class StreamingHubClient + [Obsolete("Use ConnectAsync instead.")] + public static TStreamingHub Connect(ChannelBase channel, TReceiver receiver, string? host = null, CallOptions option = default(CallOptions), IMagicOnionSerializerProvider? serializerProvider = null, IStreamingHubClientFactoryProvider? factoryProvider = null, IMagicOnionClientLogger? logger = null) + where TStreamingHub : IStreamingHub { - [Obsolete("Use ConnectAsync instead.")] - public static TStreamingHub Connect(ChannelBase channel, TReceiver receiver, string? host = null, CallOptions option = default(CallOptions), IMagicOnionSerializerProvider? serializerProvider = null, IStreamingHubClientFactoryProvider? factoryProvider = null, IMagicOnionClientLogger? logger = null) - where TStreamingHub : IStreamingHub + var hubClient = Connect(channel.CreateCallInvoker(), receiver, host, option, serializerProvider, factoryProvider, logger); + // ReSharper disable once SuspiciousTypeConversion.Global + if (channel is IMagicOnionAwareGrpcChannel magicOnionAwareGrpcChannel) { - var hubClient = Connect(channel.CreateCallInvoker(), receiver, host, option, serializerProvider, factoryProvider, logger); - // ReSharper disable once SuspiciousTypeConversion.Global - if (channel is IMagicOnionAwareGrpcChannel magicOnionAwareGrpcChannel) - { - magicOnionAwareGrpcChannel.ManageStreamingHubClient(typeof(TStreamingHub), hubClient, hubClient.DisposeAsync, hubClient.WaitForDisconnect()); - } - return hubClient; + magicOnionAwareGrpcChannel.ManageStreamingHubClient(typeof(TStreamingHub), hubClient, hubClient.DisposeAsync, hubClient.WaitForDisconnect()); } + return hubClient; + } - public static Task ConnectAsync(ChannelBase channel, TReceiver receiver, string? host = null, CallOptions option = default(CallOptions), IMagicOnionSerializerProvider? serializerProvider = null, IStreamingHubClientFactoryProvider? factoryProvider = null, IMagicOnionClientLogger? logger = null, CancellationToken cancellationToken = default) - where TStreamingHub : IStreamingHub + public static Task ConnectAsync(ChannelBase channel, TReceiver receiver, string? host = null, CallOptions option = default(CallOptions), IMagicOnionSerializerProvider? serializerProvider = null, IStreamingHubClientFactoryProvider? factoryProvider = null, IMagicOnionClientLogger? logger = null, CancellationToken cancellationToken = default) + where TStreamingHub : IStreamingHub + { + var options = StreamingHubClientOptions.CreateWithDefault(host, option, serializerProvider, logger); + return ConnectAsync(channel, receiver, options, factoryProvider, cancellationToken); + } + + public static async Task ConnectAsync(ChannelBase channel, TReceiver receiver, StreamingHubClientOptions options, IStreamingHubClientFactoryProvider? factoryProvider = null, CancellationToken cancellationToken = default) + where TStreamingHub : IStreamingHub + { + var hubClient = await ConnectAsync(channel.CreateCallInvoker(), receiver, options, factoryProvider, cancellationToken); + // ReSharper disable once SuspiciousTypeConversion.Global + if (channel is IMagicOnionAwareGrpcChannel magicOnionAwareGrpcChannel) { - var options = StreamingHubClientOptions.CreateWithDefault(host, option, serializerProvider, logger); - return ConnectAsync(channel, receiver, options, factoryProvider, cancellationToken); + magicOnionAwareGrpcChannel.ManageStreamingHubClient(typeof(TStreamingHub), hubClient, hubClient.DisposeAsync, hubClient.WaitForDisconnect()); } + return hubClient; + } + + [Obsolete("Use ConnectAsync instead.")] + public static TStreamingHub Connect(CallInvoker callInvoker, TReceiver receiver, string? host = null, CallOptions option = default(CallOptions), IMagicOnionSerializerProvider? serializerProvider = null, IStreamingHubClientFactoryProvider? factoryProvider = null, IMagicOnionClientLogger? logger = null) + where TStreamingHub : IStreamingHub + { + var options = StreamingHubClientOptions.CreateWithDefault(host, option); + var client = CreateClient(receiver, callInvoker, options, factoryProvider); - public static async Task ConnectAsync(ChannelBase channel, TReceiver receiver, StreamingHubClientOptions options, IStreamingHubClientFactoryProvider? factoryProvider = null, CancellationToken cancellationToken = default) - where TStreamingHub : IStreamingHub + async void ConnectAndForget() { - var hubClient = await ConnectAsync(channel.CreateCallInvoker(), receiver, options, factoryProvider, cancellationToken); - // ReSharper disable once SuspiciousTypeConversion.Global - if (channel is IMagicOnionAwareGrpcChannel magicOnionAwareGrpcChannel) + var task = client.__ConnectAndSubscribeAsync(CancellationToken.None); + try + { + await task.ConfigureAwait(false); + } + catch (Exception e) { - magicOnionAwareGrpcChannel.ManageStreamingHubClient(typeof(TStreamingHub), hubClient, hubClient.DisposeAsync, hubClient.WaitForDisconnect()); + logger?.Error(e, "An error occurred while connecting to the server."); } - return hubClient; } - [Obsolete("Use ConnectAsync instead.")] - public static TStreamingHub Connect(CallInvoker callInvoker, TReceiver receiver, string? host = null, CallOptions option = default(CallOptions), IMagicOnionSerializerProvider? serializerProvider = null, IStreamingHubClientFactoryProvider? factoryProvider = null, IMagicOnionClientLogger? logger = null) - where TStreamingHub : IStreamingHub - { - var options = StreamingHubClientOptions.CreateWithDefault(host, option); - var client = CreateClient(receiver, callInvoker, options, factoryProvider); + ConnectAndForget(); - async void ConnectAndForget() - { - var task = client.__ConnectAndSubscribeAsync(CancellationToken.None); - try - { - await task.ConfigureAwait(false); - } - catch (Exception e) - { - logger?.Error(e, "An error occurred while connecting to the server."); - } - } + return (TStreamingHub)(object)client; + } - ConnectAndForget(); + public static Task ConnectAsync(CallInvoker callInvoker, TReceiver receiver, string? host = null, CallOptions option = default(CallOptions), IMagicOnionSerializerProvider? serializerProvider = null, IStreamingHubClientFactoryProvider? factoryProvider = null, IMagicOnionClientLogger? logger = null, CancellationToken cancellationToken = default) + where TStreamingHub : IStreamingHub + { + var options = StreamingHubClientOptions.CreateWithDefault(host, option, serializerProvider, logger); + return ConnectAsync(callInvoker, receiver, options, factoryProvider, cancellationToken); + } - return (TStreamingHub)(object)client; - } + public static async Task ConnectAsync(CallInvoker callInvoker, TReceiver receiver, StreamingHubClientOptions options, IStreamingHubClientFactoryProvider? factoryProvider = null, CancellationToken cancellationToken = default) + where TStreamingHub : IStreamingHub + { + var client = CreateClient(receiver, callInvoker, options, factoryProvider); + await client.__ConnectAndSubscribeAsync(cancellationToken).ConfigureAwait(false); + return (TStreamingHub)(object)client; + } - public static Task ConnectAsync(CallInvoker callInvoker, TReceiver receiver, string? host = null, CallOptions option = default(CallOptions), IMagicOnionSerializerProvider? serializerProvider = null, IStreamingHubClientFactoryProvider? factoryProvider = null, IMagicOnionClientLogger? logger = null, CancellationToken cancellationToken = default) - where TStreamingHub : IStreamingHub - { - var options = StreamingHubClientOptions.CreateWithDefault(host, option, serializerProvider, logger); - return ConnectAsync(callInvoker, receiver, options, factoryProvider, cancellationToken); - } + static StreamingHubClientBase CreateClient(TReceiver receiver, CallInvoker callInvoker, StreamingHubClientOptions options, IStreamingHubClientFactoryProvider? factoryProvider) + where TStreamingHub : IStreamingHub + { + factoryProvider ??= StreamingHubClientFactoryProvider.Default; - public static async Task ConnectAsync(CallInvoker callInvoker, TReceiver receiver, StreamingHubClientOptions options, IStreamingHubClientFactoryProvider? factoryProvider = null, CancellationToken cancellationToken = default) - where TStreamingHub : IStreamingHub + if (!factoryProvider.TryGetFactory(out var factory)) { - var client = CreateClient(receiver, callInvoker, options, factoryProvider); - await client.__ConnectAndSubscribeAsync(cancellationToken).ConfigureAwait(false); - return (TStreamingHub)(object)client; + throw new NotSupportedException($"Unable to get client factory for StreamingHub type '{typeof(TStreamingHub).FullName}'."); } - static StreamingHubClientBase CreateClient(TReceiver receiver, CallInvoker callInvoker, StreamingHubClientOptions options, IStreamingHubClientFactoryProvider? factoryProvider) - where TStreamingHub : IStreamingHub - { - factoryProvider ??= StreamingHubClientFactoryProvider.Default; - - if (!factoryProvider.TryGetFactory(out var factory)) - { - throw new NotSupportedException($"Unable to get client factory for StreamingHub type '{typeof(TStreamingHub).FullName}'."); - } - - return (StreamingHubClientBase)(object)factory(receiver, callInvoker, options); - } + return (StreamingHubClientBase)(object)factory(receiver, callInvoker, options); } } diff --git a/src/MagicOnion.Client/StreamingHubClientBase.cs b/src/MagicOnion.Client/StreamingHubClientBase.cs index 1a0f95ccc..34122c879 100644 --- a/src/MagicOnion.Client/StreamingHubClientBase.cs +++ b/src/MagicOnion.Client/StreamingHubClientBase.cs @@ -6,731 +6,730 @@ using MagicOnion.Internal.Buffers; using MagicOnion.Client.Internal; -namespace MagicOnion.Client +namespace MagicOnion.Client; + +public class StreamingHubClientOptions { - public class StreamingHubClientOptions + public string? Host { get; } + public CallOptions CallOptions { get; } + public IMagicOnionSerializerProvider SerializerProvider { get; } + public IMagicOnionClientLogger Logger { get; } + + public TimeSpan? ClientHeartbeatInterval { get; } + public TimeSpan? ClientHeartbeatTimeout { get; } + public Action? OnServerHeartbeatReceived { get; } + public Action? OnClientHeartbeatResponseReceived { get; } + public TimeProvider? TimeProvider { get; } + + public StreamingHubClientOptions(string? host, CallOptions callOptions, IMagicOnionSerializerProvider serializerProvider, IMagicOnionClientLogger logger) + : this(host, callOptions, serializerProvider, logger, default, default, default, default, default) { - public string? Host { get; } - public CallOptions CallOptions { get; } - public IMagicOnionSerializerProvider SerializerProvider { get; } - public IMagicOnionClientLogger Logger { get; } - - public TimeSpan? ClientHeartbeatInterval { get; } - public TimeSpan? ClientHeartbeatTimeout { get; } - public Action? OnServerHeartbeatReceived { get; } - public Action? OnClientHeartbeatResponseReceived { get; } - public TimeProvider? TimeProvider { get; } - - public StreamingHubClientOptions(string? host, CallOptions callOptions, IMagicOnionSerializerProvider serializerProvider, IMagicOnionClientLogger logger) - : this(host, callOptions, serializerProvider, logger, default, default, default, default, default) - { - } - - public StreamingHubClientOptions(string? host, CallOptions callOptions, IMagicOnionSerializerProvider serializerProvider, IMagicOnionClientLogger logger, TimeSpan? clientHeartbeatInterval, TimeSpan? clientHeartbeatTimeout, Action? onServerHeartbeatReceived, Action? onClientHeartbeatResponseReceived,TimeProvider? timeProvider) - { - Host = host; - CallOptions = callOptions; - SerializerProvider = serializerProvider ?? throw new ArgumentNullException(nameof(serializerProvider)); - Logger = logger ?? throw new ArgumentNullException(nameof(logger)); - ClientHeartbeatInterval = clientHeartbeatInterval; - ClientHeartbeatTimeout = clientHeartbeatTimeout; - OnServerHeartbeatReceived = onServerHeartbeatReceived; - OnClientHeartbeatResponseReceived = onClientHeartbeatResponseReceived; - TimeProvider = timeProvider; - } - - public static StreamingHubClientOptions CreateWithDefault(string? host = default, CallOptions callOptions = default, IMagicOnionSerializerProvider? serializerProvider = default, IMagicOnionClientLogger? logger = default) - => new(host, callOptions, serializerProvider ?? MagicOnionSerializerProvider.Default, logger ?? NullMagicOnionClientLogger.Instance); - - public StreamingHubClientOptions WithHost(string? host) - => new(host, CallOptions, SerializerProvider, Logger - , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived - , TimeProvider - ); - public StreamingHubClientOptions WithCallOptions(CallOptions callOptions) - => new(Host, callOptions, SerializerProvider, Logger - , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived - , TimeProvider - ); - public StreamingHubClientOptions WithSerializerProvider(IMagicOnionSerializerProvider serializerProvider) - => new( - Host, CallOptions, serializerProvider, Logger - , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived - , TimeProvider - ); - public StreamingHubClientOptions WithLogger(IMagicOnionClientLogger logger) - => new(Host, CallOptions, SerializerProvider, logger - , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived - , TimeProvider - ); - - /// - /// Sets a heartbeat interval. If a value is , the heartbeat from the client is disabled. - /// - /// - /// - public StreamingHubClientOptions WithClientHeartbeatInterval(TimeSpan? interval) - => new(Host, CallOptions, SerializerProvider, Logger - , interval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived - , TimeProvider - ); - - /// - /// Sets a heartbeat timeout period. If a value is , the client does not time out. - /// - /// - /// - public StreamingHubClientOptions WithClientHeartbeatTimeout(TimeSpan? timeout) - => new(Host, CallOptions, SerializerProvider, Logger - , ClientHeartbeatInterval, timeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived - , TimeProvider - ); - - /// - /// Sets a heartbeat callback. If additional metadata is provided by the server in the heartbeat message, this metadata is provided as an argument. - /// - /// - /// - public StreamingHubClientOptions WithServerHeartbeatReceived(Action? onServerHeartbeatReceived) - => new(Host, CallOptions, SerializerProvider, Logger - , ClientHeartbeatInterval, ClientHeartbeatTimeout, onServerHeartbeatReceived, OnClientHeartbeatResponseReceived - , TimeProvider - ); - - /// - /// Sets a client heartbeat response callback. - /// - /// - /// - public StreamingHubClientOptions WithClientHeartbeatResponseReceived(Action? onClientHeartbeatResponseReceived) - => new(Host, CallOptions, SerializerProvider, Logger - , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, onClientHeartbeatResponseReceived - , TimeProvider - ); - - /// - /// Sets a - /// - /// - /// - public StreamingHubClientOptions WithTimeProvider(TimeProvider timeProvider) - => new(Host, CallOptions, SerializerProvider, Logger - , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived - , timeProvider - ); } - public abstract class StreamingHubClientBase : IStreamingHubClient - where TStreamingHub : IStreamingHub + public StreamingHubClientOptions(string? host, CallOptions callOptions, IMagicOnionSerializerProvider serializerProvider, IMagicOnionClientLogger logger, TimeSpan? clientHeartbeatInterval, TimeSpan? clientHeartbeatTimeout, Action? onServerHeartbeatReceived, Action? onClientHeartbeatResponseReceived,TimeProvider? timeProvider) { + Host = host; + CallOptions = callOptions; + SerializerProvider = serializerProvider ?? throw new ArgumentNullException(nameof(serializerProvider)); + Logger = logger ?? throw new ArgumentNullException(nameof(logger)); + ClientHeartbeatInterval = clientHeartbeatInterval; + ClientHeartbeatTimeout = clientHeartbeatTimeout; + OnServerHeartbeatReceived = onServerHeartbeatReceived; + OnClientHeartbeatResponseReceived = onClientHeartbeatResponseReceived; + TimeProvider = timeProvider; + } + + public static StreamingHubClientOptions CreateWithDefault(string? host = default, CallOptions callOptions = default, IMagicOnionSerializerProvider? serializerProvider = default, IMagicOnionClientLogger? logger = default) + => new(host, callOptions, serializerProvider ?? MagicOnionSerializerProvider.Default, logger ?? NullMagicOnionClientLogger.Instance); + + public StreamingHubClientOptions WithHost(string? host) + => new(host, CallOptions, SerializerProvider, Logger + , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived + , TimeProvider + ); + public StreamingHubClientOptions WithCallOptions(CallOptions callOptions) + => new(Host, callOptions, SerializerProvider, Logger + , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived + , TimeProvider + ); + public StreamingHubClientOptions WithSerializerProvider(IMagicOnionSerializerProvider serializerProvider) + => new( + Host, CallOptions, serializerProvider, Logger + , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived + , TimeProvider + ); + public StreamingHubClientOptions WithLogger(IMagicOnionClientLogger logger) + => new(Host, CallOptions, SerializerProvider, logger + , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived + , TimeProvider + ); + + /// + /// Sets a heartbeat interval. If a value is , the heartbeat from the client is disabled. + /// + /// + /// + public StreamingHubClientOptions WithClientHeartbeatInterval(TimeSpan? interval) + => new(Host, CallOptions, SerializerProvider, Logger + , interval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived + , TimeProvider + ); + + /// + /// Sets a heartbeat timeout period. If a value is , the client does not time out. + /// + /// + /// + public StreamingHubClientOptions WithClientHeartbeatTimeout(TimeSpan? timeout) + => new(Host, CallOptions, SerializerProvider, Logger + , ClientHeartbeatInterval, timeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived + , TimeProvider + ); + + /// + /// Sets a heartbeat callback. If additional metadata is provided by the server in the heartbeat message, this metadata is provided as an argument. + /// + /// + /// + public StreamingHubClientOptions WithServerHeartbeatReceived(Action? onServerHeartbeatReceived) + => new(Host, CallOptions, SerializerProvider, Logger + , ClientHeartbeatInterval, ClientHeartbeatTimeout, onServerHeartbeatReceived, OnClientHeartbeatResponseReceived + , TimeProvider + ); + + /// + /// Sets a client heartbeat response callback. + /// + /// + /// + public StreamingHubClientOptions WithClientHeartbeatResponseReceived(Action? onClientHeartbeatResponseReceived) + => new(Host, CallOptions, SerializerProvider, Logger + , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, onClientHeartbeatResponseReceived + , TimeProvider + ); + + /// + /// Sets a + /// + /// + /// + public StreamingHubClientOptions WithTimeProvider(TimeProvider timeProvider) + => new(Host, CallOptions, SerializerProvider, Logger + , ClientHeartbeatInterval, ClientHeartbeatTimeout, OnServerHeartbeatReceived, OnClientHeartbeatResponseReceived + , timeProvider + ); +} + +public abstract class StreamingHubClientBase : IStreamingHubClient + where TStreamingHub : IStreamingHub +{ #pragma warning disable IDE1006 // Naming Styles - const string StreamingHubVersionHeaderKey = "x-magiconion-streaminghub-version"; - const string StreamingHubVersionHeaderValue = "2"; + const string StreamingHubVersionHeaderKey = "x-magiconion-streaminghub-version"; + const string StreamingHubVersionHeaderValue = "2"; #pragma warning restore IDE1006 // Naming Styles - readonly CallInvoker callInvoker; - readonly StreamingHubClientOptions options; - readonly IMagicOnionClientLogger logger; - readonly IMagicOnionSerializer messageSerializer; - readonly Method duplexStreamingConnectMethod; - // {messageId, TaskCompletionSource} - readonly Dictionary responseFutures = new(); - readonly TaskCompletionSource waitForDisconnect = new(); - readonly CancellationTokenSource subscriptionCts = new(); - readonly Dictionary postCallbackCache = new(); + readonly CallInvoker callInvoker; + readonly StreamingHubClientOptions options; + readonly IMagicOnionClientLogger logger; + readonly IMagicOnionSerializer messageSerializer; + readonly Method duplexStreamingConnectMethod; + // {messageId, TaskCompletionSource} + readonly Dictionary responseFutures = new(); + readonly TaskCompletionSource waitForDisconnect = new(); + readonly CancellationTokenSource subscriptionCts = new(); + readonly Dictionary postCallbackCache = new(); + + int messageIdSequence = 0; + bool disposed; + bool disconnected; + int cleanupSentinel = 0; // 0 = false, 1 = true + + readonly Channel writerQueue = Channel.CreateUnbounded(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = false, AllowSynchronousContinuations = false }); + Task? writerTask; + IClientStreamWriter writer = default!; + IAsyncStreamReader reader = default!; + + StreamingHubClientHeartbeatManager heartbeatManager = default!; + Task subscription = default!; + + protected readonly TReceiver receiver; + + protected StreamingHubClientBase(string serviceName, TReceiver receiver, CallInvoker callInvoker, StreamingHubClientOptions options) + { + this.callInvoker = callInvoker; + this.receiver = receiver; + this.options = options; + this.logger = options.Logger; + this.duplexStreamingConnectMethod = CreateConnectMethod(serviceName); + this.messageSerializer = options.SerializerProvider.Create(MethodType.DuplexStreaming, null); + } - int messageIdSequence = 0; - bool disposed; - bool disconnected; - int cleanupSentinel = 0; // 0 = false, 1 = true + // call immediately after create. + internal async Task __ConnectAndSubscribeAsync(CancellationToken connectAndSubscribeCancellationToken) + { + var syncContext = SynchronizationContext.Current; // capture SynchronizationContext. + var callResult = callInvoker.AsyncDuplexStreamingCall(duplexStreamingConnectMethod, options.Host, options.CallOptions); - readonly Channel writerQueue = Channel.CreateUnbounded(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = false, AllowSynchronousContinuations = false }); - Task? writerTask; - IClientStreamWriter writer = default!; - IAsyncStreamReader reader = default!; + this.writer = callResult.RequestStream; + this.reader = callResult.ResponseStream; - StreamingHubClientHeartbeatManager heartbeatManager = default!; - Task subscription = default!; + // Establish StreamingHub connection between the client and the server. + Metadata.Entry? messageVersion; + try + { + // The client can read the response headers before any StreamingHub's message. + // MagicOnion.Server v4.0.x or before doesn't send any response headers. The client is incompatible with that versions. + // NOTE: Grpc.Net: + // If the channel can not be connected, ResponseHeadersAsync will throw an exception. + // C-core: + // If the channel can not be connected, ResponseHeadersAsync will **return** an empty metadata. + var headers = await callResult.ResponseHeadersAsync.ConfigureAwait(false); + messageVersion = headers.FirstOrDefault(x => x.Key == StreamingHubVersionHeaderKey); - protected readonly TReceiver receiver; + connectAndSubscribeCancellationToken.ThrowIfCancellationRequested(); - protected StreamingHubClientBase(string serviceName, TReceiver receiver, CallInvoker callInvoker, StreamingHubClientOptions options) + // Check message version of StreamingHub. + if (messageVersion != null && messageVersion.Value != StreamingHubVersionHeaderValue) + { + throw new RpcException(new Status(StatusCode.Internal, $"The message version of StreamingHub mismatch between the client and the server. (ServerVersion={messageVersion?.Value}; Expected={StreamingHubVersionHeaderValue})")); + } + } + catch (RpcException e) { - this.callInvoker = callInvoker; - this.receiver = receiver; - this.options = options; - this.logger = options.Logger; - this.duplexStreamingConnectMethod = CreateConnectMethod(serviceName); - this.messageSerializer = options.SerializerProvider.Create(MethodType.DuplexStreaming, null); + throw new RpcException(e.Status, $"Failed to connect to StreamingHub '{duplexStreamingConnectMethod.ServiceName}'. ({e.Status})"); } - // call immediately after create. - internal async Task __ConnectAndSubscribeAsync(CancellationToken connectAndSubscribeCancellationToken) + // Set up the Heartbeat Manager + heartbeatManager = new StreamingHubClientHeartbeatManager( + writerQueue.Writer, + options.ClientHeartbeatInterval ?? TimeSpan.Zero /* Disable */, + options.ClientHeartbeatTimeout ?? Timeout.InfiniteTimeSpan, + options.OnServerHeartbeatReceived, + options.OnClientHeartbeatResponseReceived, + syncContext, + options.TimeProvider ?? TimeProvider.System + ); + + // Activate the Heartbeat Manager if enabled in the options. + var subscriptionToken = subscriptionCts.Token; + if (options.ClientHeartbeatInterval is { } heartbeatInterval && heartbeatInterval > TimeSpan.Zero) { - var syncContext = SynchronizationContext.Current; // capture SynchronizationContext. - var callResult = callInvoker.AsyncDuplexStreamingCall(duplexStreamingConnectMethod, options.Host, options.CallOptions); - - this.writer = callResult.RequestStream; - this.reader = callResult.ResponseStream; - - // Establish StreamingHub connection between the client and the server. - Metadata.Entry? messageVersion; - try - { - // The client can read the response headers before any StreamingHub's message. - // MagicOnion.Server v4.0.x or before doesn't send any response headers. The client is incompatible with that versions. - // NOTE: Grpc.Net: - // If the channel can not be connected, ResponseHeadersAsync will throw an exception. - // C-core: - // If the channel can not be connected, ResponseHeadersAsync will **return** an empty metadata. - var headers = await callResult.ResponseHeadersAsync.ConfigureAwait(false); - messageVersion = headers.FirstOrDefault(x => x.Key == StreamingHubVersionHeaderKey); - - connectAndSubscribeCancellationToken.ThrowIfCancellationRequested(); - - // Check message version of StreamingHub. - if (messageVersion != null && messageVersion.Value != StreamingHubVersionHeaderValue) - { - throw new RpcException(new Status(StatusCode.Internal, $"The message version of StreamingHub mismatch between the client and the server. (ServerVersion={messageVersion?.Value}; Expected={StreamingHubVersionHeaderValue})")); - } - } - catch (RpcException e) - { - throw new RpcException(e.Status, $"Failed to connect to StreamingHub '{duplexStreamingConnectMethod.ServiceName}'. ({e.Status})"); - } + heartbeatManager.StartClientHeartbeatLoop(); + subscriptionToken = CancellationTokenSource.CreateLinkedTokenSource(heartbeatManager.TimeoutToken, subscriptionCts.Token).Token; + } - // Set up the Heartbeat Manager - heartbeatManager = new StreamingHubClientHeartbeatManager( - writerQueue.Writer, - options.ClientHeartbeatInterval ?? TimeSpan.Zero /* Disable */, - options.ClientHeartbeatTimeout ?? Timeout.InfiniteTimeSpan, - options.OnServerHeartbeatReceived, - options.OnClientHeartbeatResponseReceived, - syncContext, - options.TimeProvider ?? TimeProvider.System - ); - - // Activate the Heartbeat Manager if enabled in the options. - var subscriptionToken = subscriptionCts.Token; - if (options.ClientHeartbeatInterval is { } heartbeatInterval && heartbeatInterval > TimeSpan.Zero) - { - heartbeatManager.StartClientHeartbeatLoop(); - subscriptionToken = CancellationTokenSource.CreateLinkedTokenSource(heartbeatManager.TimeoutToken, subscriptionCts.Token).Token; - } + var firstMoveNextTask = reader.MoveNext(CancellationTokenSource.CreateLinkedTokenSource(connectAndSubscribeCancellationToken, subscriptionToken).Token); + if (firstMoveNextTask.IsFaulted || messageVersion == null) + { + // NOTE: Grpc.Net: + // If an error is returned from `StreamingHub.Connect` method on a server-side, + // ResponseStream.MoveNext synchronously returns a task that is `IsFaulted = true`. + // `ConnectAsync` method should throw an exception here immediately. + // C-core: + // `firstMoveNextTask` is incomplete task (`IsFaulted = false`) whether ResponseHeadersAsync is failed or not. + // If the channel is disconnected or the server returns an error (StatusCode != OK), awaiting the Task will throw an exception. + await firstMoveNextTask.ConfigureAwait(false); + + // NOTE: C-core: If the execution reaches here, Connect method returns without any error (StatusCode = OK). but MessageVersion isn't provided from the server. + throw new RpcException(new Status(StatusCode.Internal, $"The request started successfully (StatusCode = OK), but the StreamingHub client has failed to negotiate with the server.")); + } - var firstMoveNextTask = reader.MoveNext(CancellationTokenSource.CreateLinkedTokenSource(connectAndSubscribeCancellationToken, subscriptionToken).Token); - if (firstMoveNextTask.IsFaulted || messageVersion == null) - { - // NOTE: Grpc.Net: - // If an error is returned from `StreamingHub.Connect` method on a server-side, - // ResponseStream.MoveNext synchronously returns a task that is `IsFaulted = true`. - // `ConnectAsync` method should throw an exception here immediately. - // C-core: - // `firstMoveNextTask` is incomplete task (`IsFaulted = false`) whether ResponseHeadersAsync is failed or not. - // If the channel is disconnected or the server returns an error (StatusCode != OK), awaiting the Task will throw an exception. - await firstMoveNextTask.ConfigureAwait(false); - - // NOTE: C-core: If the execution reaches here, Connect method returns without any error (StatusCode = OK). but MessageVersion isn't provided from the server. - throw new RpcException(new Status(StatusCode.Internal, $"The request started successfully (StatusCode = OK), but the StreamingHub client has failed to negotiate with the server.")); - } + this.subscription = StartSubscribe(syncContext, firstMoveNextTask, subscriptionToken); + } - this.subscription = StartSubscribe(syncContext, firstMoveNextTask, subscriptionToken); - } + // Helper methods to make building clients easy. + protected void SetResultForResponse(object taskSource, ReadOnlyMemory data) + => ((StreamingHubResponseTaskSource)taskSource).SetResult(Deserialize(data)); + protected void Serialize(IBufferWriter writer, in T value) + => messageSerializer.Serialize(writer, value); + protected T Deserialize(ReadOnlyMemory data) + => messageSerializer.Deserialize(new ReadOnlySequence(data)); - // Helper methods to make building clients easy. - protected void SetResultForResponse(object taskSource, ReadOnlyMemory data) - => ((StreamingHubResponseTaskSource)taskSource).SetResult(Deserialize(data)); - protected void Serialize(IBufferWriter writer, in T value) - => messageSerializer.Serialize(writer, value); - protected T Deserialize(ReadOnlyMemory data) - => messageSerializer.Deserialize(new ReadOnlySequence(data)); + protected abstract void OnClientResultEvent(int methodId, Guid messageId, ReadOnlyMemory data); + protected abstract void OnResponseEvent(int methodId, object taskSource, ReadOnlyMemory data); + protected abstract void OnBroadcastEvent(int methodId, ReadOnlyMemory data); - protected abstract void OnClientResultEvent(int methodId, Guid messageId, ReadOnlyMemory data); - protected abstract void OnResponseEvent(int methodId, object taskSource, ReadOnlyMemory data); - protected abstract void OnBroadcastEvent(int methodId, ReadOnlyMemory data); + static Method CreateConnectMethod(string serviceName) + => new (MethodType.DuplexStreaming, serviceName, "Connect", MagicOnionMarshallers.StreamingHubMarshaller, MagicOnionMarshallers.StreamingHubMarshaller); - static Method CreateConnectMethod(string serviceName) - => new (MethodType.DuplexStreaming, serviceName, "Connect", MagicOnionMarshallers.StreamingHubMarshaller, MagicOnionMarshallers.StreamingHubMarshaller); + async Task StartSubscribe(SynchronizationContext? syncContext, Task firstMoveNext, CancellationToken subscriptionToken) + { + var disconnectionReason = new DisconnectionReason(DisconnectionType.CompletedNormally, null); + writerTask = RunWriterLoopAsync(subscriptionToken); - async Task StartSubscribe(SynchronizationContext? syncContext, Task firstMoveNext, CancellationToken subscriptionToken) + var reader = this.reader; + try { - var disconnectionReason = new DisconnectionReason(DisconnectionType.CompletedNormally, null); - writerTask = RunWriterLoopAsync(subscriptionToken); - - var reader = this.reader; - try + var moveNext = firstMoveNext; + while (await moveNext.ConfigureAwait(false)) // avoid Post to SyncContext(it losts one-frame per operation) { - var moveNext = firstMoveNext; - while (await moveNext.ConfigureAwait(false)) // avoid Post to SyncContext(it losts one-frame per operation) + try { - try - { - ConsumeData(syncContext, reader.Current); - } - catch (Exception ex) - { - const string msg = "An error occurred when consuming a received message, but the subscription is still alive."; - // log post on main thread. - if (syncContext != null) - { - syncContext.Post(s => logger.Error((Exception)s!, msg), ex); - } - else - { - logger.Error(ex, msg); - } - } - - moveNext = reader.MoveNext(subscriptionToken); + ConsumeData(syncContext, reader.Current); } - } - catch (Exception ex) - { - // When terminating by Heartbeat or DisposeAsync, a RpcException with a Status of Canceled is thrown. - // If `ex.InnerException` is OperationCanceledException` and `subscriptionToken.IsCancellationRequested` is true, it is treated as a normal cancellation. - if ((ex is OperationCanceledException oce) || - (ex is RpcException { InnerException: OperationCanceledException } && subscriptionToken.IsCancellationRequested)) + catch (Exception ex) { - if (heartbeatManager.TimeoutToken.IsCancellationRequested) + const string msg = "An error occurred when consuming a received message, but the subscription is still alive."; + // log post on main thread. + if (syncContext != null) { - disconnectionReason = new DisconnectionReason(DisconnectionType.TimedOut, ex); + syncContext.Post(s => logger.Error((Exception)s!, msg), ex); } - return; - } - - const string msg = "An error occurred while subscribing to messages."; - // log post on main thread. - if (syncContext != null) - { - syncContext.Post(s => logger.Error((Exception)s!, msg), ex); - } - else - { - logger.Error(ex, msg); - } - - disconnectionReason = new DisconnectionReason(DisconnectionType.Faulted, ex); - } - finally - { - disconnected = true; - - try - { -#if !UNITY_WEBGL - // set syncContext before await - // NOTE: If restore SynchronizationContext in WebGL environment, a continuation will not be executed inline and will be stuck. - if (syncContext != null && SynchronizationContext.Current == null) + else { - SynchronizationContext.SetSynchronizationContext(syncContext); + logger.Error(ex, msg); } -#endif - await heartbeatManager.DisposeAsync().ConfigureAwait(false); - await CleanupAsync(false).ConfigureAwait(false); - } - finally - { - waitForDisconnect.TrySetResult(disconnectionReason); } + + moveNext = reader.MoveNext(subscriptionToken); } } - - void ConsumeData(SynchronizationContext? syncContext, StreamingHubPayload payload) + catch (Exception ex) { - var messageReader = new StreamingHubClientMessageReader(payload.Memory); - switch (messageReader.ReadMessageType()) + // When terminating by Heartbeat or DisposeAsync, a RpcException with a Status of Canceled is thrown. + // If `ex.InnerException` is OperationCanceledException` and `subscriptionToken.IsCancellationRequested` is true, it is treated as a normal cancellation. + if ((ex is OperationCanceledException oce) || + (ex is RpcException { InnerException: OperationCanceledException } && subscriptionToken.IsCancellationRequested)) { - case StreamingHubMessageType.Broadcast: - ProcessBroadcast(syncContext, payload, ref messageReader); - break; - case StreamingHubMessageType.Response: - ProcessResponse(syncContext, payload, ref messageReader); - break; - case StreamingHubMessageType.ResponseWithError: - ProcessResponseWithError(syncContext, payload, ref messageReader); - break; - case StreamingHubMessageType.ClientResultRequest: - ProcessClientResultRequest(syncContext, payload, ref messageReader); - break; - case StreamingHubMessageType.ServerHeartbeat: - heartbeatManager.ProcessServerHeartbeat(payload); - break; - case StreamingHubMessageType.ClientHeartbeatResponse: - heartbeatManager.ProcessClientHeartbeatResponse(payload); - break; + if (heartbeatManager.TimeoutToken.IsCancellationRequested) + { + disconnectionReason = new DisconnectionReason(DisconnectionType.TimedOut, ex); + } + return; } - } - void ProcessBroadcast(SynchronizationContext? syncContext, StreamingHubPayload payload, ref StreamingHubClientMessageReader messageReader) - { - if (syncContext is null) + const string msg = "An error occurred while subscribing to messages."; + // log post on main thread. + if (syncContext != null) { - var message = messageReader.ReadBroadcastMessage(); - OnBroadcastEvent(message.MethodId, message.Body); - StreamingHubPayloadPool.Shared.Return(payload); + syncContext.Post(s => logger.Error((Exception)s!, msg), ex); } else { - var (methodId, consumed) = messageReader.ReadBroadcastMessageMethodId(); - if (!postCallbackCache.TryGetValue(methodId, out var postCallback)) - { - // Create and cache a callback delegate capturing `this` and the header size. - postCallback = postCallbackCache[methodId] = CreateBroadcastCallback(methodId, consumed); - } - syncContext.Post(postCallback, payload); + logger.Error(ex, msg); } - } - SendOrPostCallback CreateBroadcastCallback(int methodId, int consumed) - { - return (s) => - { - var p = (StreamingHubPayload)s!; - this.OnBroadcastEvent(methodId, p.Memory.Slice(consumed)); - StreamingHubPayloadPool.Shared.Return(p); - }; + disconnectionReason = new DisconnectionReason(DisconnectionType.Faulted, ex); } - - void ProcessResponse(SynchronizationContext? syncContext, StreamingHubPayload payload, ref StreamingHubClientMessageReader messageReader) + finally { - var message = messageReader.ReadResponseMessage(); + disconnected = true; - IStreamingHubResponseTaskSource? future; - lock (responseFutures) + try { - if (!responseFutures.Remove(message.MessageId, out future)) +#if !UNITY_WEBGL + // set syncContext before await + // NOTE: If restore SynchronizationContext in WebGL environment, a continuation will not be executed inline and will be stuck. + if (syncContext != null && SynchronizationContext.Current == null) { - return; + SynchronizationContext.SetSynchronizationContext(syncContext); } +#endif + await heartbeatManager.DisposeAsync().ConfigureAwait(false); + await CleanupAsync(false).ConfigureAwait(false); } - - try + finally { - OnResponseEvent(message.MethodId, future, message.Body); - StreamingHubPayloadPool.Shared.Return(payload); + waitForDisconnect.TrySetResult(disconnectionReason); } - catch (Exception ex) + } + } + + void ConsumeData(SynchronizationContext? syncContext, StreamingHubPayload payload) + { + var messageReader = new StreamingHubClientMessageReader(payload.Memory); + switch (messageReader.ReadMessageType()) + { + case StreamingHubMessageType.Broadcast: + ProcessBroadcast(syncContext, payload, ref messageReader); + break; + case StreamingHubMessageType.Response: + ProcessResponse(syncContext, payload, ref messageReader); + break; + case StreamingHubMessageType.ResponseWithError: + ProcessResponseWithError(syncContext, payload, ref messageReader); + break; + case StreamingHubMessageType.ClientResultRequest: + ProcessClientResultRequest(syncContext, payload, ref messageReader); + break; + case StreamingHubMessageType.ServerHeartbeat: + heartbeatManager.ProcessServerHeartbeat(payload); + break; + case StreamingHubMessageType.ClientHeartbeatResponse: + heartbeatManager.ProcessClientHeartbeatResponse(payload); + break; + } + } + + void ProcessBroadcast(SynchronizationContext? syncContext, StreamingHubPayload payload, ref StreamingHubClientMessageReader messageReader) + { + if (syncContext is null) + { + var message = messageReader.ReadBroadcastMessage(); + OnBroadcastEvent(message.MethodId, message.Body); + StreamingHubPayloadPool.Shared.Return(payload); + } + else + { + var (methodId, consumed) = messageReader.ReadBroadcastMessageMethodId(); + if (!postCallbackCache.TryGetValue(methodId, out var postCallback)) { - if (!future.TrySetException(ex)) - { - throw; - } + // Create and cache a callback delegate capturing `this` and the header size. + postCallback = postCallbackCache[methodId] = CreateBroadcastCallback(methodId, consumed); } + syncContext.Post(postCallback, payload); } + } - void ProcessResponseWithError(SynchronizationContext? syncContext, StreamingHubPayload payload, ref StreamingHubClientMessageReader messageReader) + SendOrPostCallback CreateBroadcastCallback(int methodId, int consumed) + { + return (s) => { - var message = messageReader.ReadResponseWithErrorMessage(); + var p = (StreamingHubPayload)s!; + this.OnBroadcastEvent(methodId, p.Memory.Slice(consumed)); + StreamingHubPayloadPool.Shared.Return(p); + }; + } - IStreamingHubResponseTaskSource? future; - lock (responseFutures) + void ProcessResponse(SynchronizationContext? syncContext, StreamingHubPayload payload, ref StreamingHubClientMessageReader messageReader) + { + var message = messageReader.ReadResponseMessage(); + + IStreamingHubResponseTaskSource? future; + lock (responseFutures) + { + if (!responseFutures.Remove(message.MessageId, out future)) { - if (!responseFutures.Remove(message.MessageId, out future)) - { - return; - } + return; } + } - RpcException ex; - if (string.IsNullOrWhiteSpace(message.Error)) + try + { + OnResponseEvent(message.MethodId, future, message.Body); + StreamingHubPayloadPool.Shared.Return(payload); + } + catch (Exception ex) + { + if (!future.TrySetException(ex)) { - ex = new RpcException(new Status((StatusCode)message.StatusCode, message.Detail ?? string.Empty)); + throw; } - else + } + } + + void ProcessResponseWithError(SynchronizationContext? syncContext, StreamingHubPayload payload, ref StreamingHubClientMessageReader messageReader) + { + var message = messageReader.ReadResponseWithErrorMessage(); + + IStreamingHubResponseTaskSource? future; + lock (responseFutures) + { + if (!responseFutures.Remove(message.MessageId, out future)) { - ex = new RpcException(new Status((StatusCode)message.StatusCode, message.Detail ?? string.Empty), message.Detail + Environment.NewLine + message.Error); + return; } + } - future.TrySetException(ex); - StreamingHubPayloadPool.Shared.Return(payload); + RpcException ex; + if (string.IsNullOrWhiteSpace(message.Error)) + { + ex = new RpcException(new Status((StatusCode)message.StatusCode, message.Detail ?? string.Empty)); + } + else + { + ex = new RpcException(new Status((StatusCode)message.StatusCode, message.Detail ?? string.Empty), message.Detail + Environment.NewLine + message.Error); } - void ProcessClientResultRequest(SynchronizationContext? syncContext, StreamingHubPayload payload, ref StreamingHubClientMessageReader messageReader) + future.TrySetException(ex); + StreamingHubPayloadPool.Shared.Return(payload); + } + + void ProcessClientResultRequest(SynchronizationContext? syncContext, StreamingHubPayload payload, ref StreamingHubClientMessageReader messageReader) + { + var message = messageReader.ReadClientResultRequestMessage(); + if (syncContext is null) { - var message = messageReader.ReadClientResultRequestMessage(); - if (syncContext is null) - { - OnClientResultEvent(message.MethodId, message.ClientResultRequestMessageId, message.Body); - StreamingHubPayloadPool.Shared.Return(payload); - } - else + OnClientResultEvent(message.MethodId, message.ClientResultRequestMessageId, message.Body); + StreamingHubPayloadPool.Shared.Return(payload); + } + else + { + var tuple = Tuple.Create(this, message.MethodId, message.ClientResultRequestMessageId, message.Body, payload); + syncContext.Post(static state => { - var tuple = Tuple.Create(this, message.MethodId, message.ClientResultRequestMessageId, message.Body, payload); - syncContext.Post(static state => - { - var t = (Tuple, int, Guid, ReadOnlyMemory, StreamingHubPayload>)state!; - t.Item1.OnClientResultEvent(t.Item2, t.Item3, t.Item4); - StreamingHubPayloadPool.Shared.Return(t.Item5); - }, tuple); - } + var t = (Tuple, int, Guid, ReadOnlyMemory, StreamingHubPayload>)state!; + t.Item1.OnClientResultEvent(t.Item2, t.Item3, t.Item4); + StreamingHubPayloadPool.Shared.Return(t.Item5); + }, tuple); } + } - async Task RunWriterLoopAsync(CancellationToken cancellationToken) + async Task RunWriterLoopAsync(CancellationToken cancellationToken) + { + try { - try + while (!cancellationToken.IsCancellationRequested) { - while (!cancellationToken.IsCancellationRequested) + if (await writerQueue.Reader.WaitToReadAsync(default).ConfigureAwait(false)) { - if (await writerQueue.Reader.WaitToReadAsync(default).ConfigureAwait(false)) + while (writerQueue.Reader.TryRead(out var payload)) { - while (writerQueue.Reader.TryRead(out var payload)) - { - cancellationToken.ThrowIfCancellationRequested(); - await writer.WriteAsync(payload).ConfigureAwait(false); - } + cancellationToken.ThrowIfCancellationRequested(); + await writer.WriteAsync(payload).ConfigureAwait(false); } } } - catch { /* Ignore */ } } + catch { /* Ignore */ } + } - protected Task WriteMessageFireAndForgetTaskAsync(int methodId, TRequest message) - => WriteMessageFireAndForgetValueTaskOfTAsync(methodId, message).AsTask(); + protected Task WriteMessageFireAndForgetTaskAsync(int methodId, TRequest message) + => WriteMessageFireAndForgetValueTaskOfTAsync(methodId, message).AsTask(); - protected ValueTask WriteMessageFireAndForgetValueTaskOfTAsync(int methodId, TRequest message) - { - ThrowIfDisposed(); - ThrowIfDisconnected(); + protected ValueTask WriteMessageFireAndForgetValueTaskOfTAsync(int methodId, TRequest message) + { + ThrowIfDisposed(); + ThrowIfDisconnected(); - var v = BuildRequestMessage(methodId, message); - _ = writerQueue.Writer.TryWrite(v); + var v = BuildRequestMessage(methodId, message); + _ = writerQueue.Writer.TryWrite(v); - return default; - } + return default; + } + + protected ValueTask WriteMessageFireAndForgetValueTaskAsync(int methodId, TRequest message) + { + WriteMessageFireAndForgetValueTaskOfTAsync(methodId, message); + return default; + } + + protected Task WriteMessageWithResponseTaskAsync(int methodId, TRequest message) + => WriteMessageWithResponseValueTaskOfTAsync(methodId, message).AsTask(); - protected ValueTask WriteMessageFireAndForgetValueTaskAsync(int methodId, TRequest message) + protected ValueTask WriteMessageWithResponseValueTaskOfTAsync(int methodId, TRequest message) + { + ThrowIfDisposed(); + ThrowIfDisconnected(); + + var mid = Interlocked.Increment(ref messageIdSequence); + + var taskSource = StreamingHubResponseTaskSourcePool.Shared.RentOrCreate(); + lock (responseFutures) { - WriteMessageFireAndForgetValueTaskOfTAsync(methodId, message); - return default; + responseFutures[mid] = taskSource; } - protected Task WriteMessageWithResponseTaskAsync(int methodId, TRequest message) - => WriteMessageWithResponseValueTaskOfTAsync(methodId, message).AsTask(); - - protected ValueTask WriteMessageWithResponseValueTaskOfTAsync(int methodId, TRequest message) + var v = BuildRequestMessage(methodId, mid, message); + if (!writerQueue.Writer.TryWrite(v)) { - ThrowIfDisposed(); + // If the channel writer is closed, it is likely that the connection has already been disconnected. ThrowIfDisconnected(); + } - var mid = Interlocked.Increment(ref messageIdSequence); + return new ValueTask(taskSource, taskSource.Version); // wait until server return response(or error). if connection was closed, throws cancellation from DisposeAsyncCore. + } - var taskSource = StreamingHubResponseTaskSourcePool.Shared.RentOrCreate(); - lock (responseFutures) - { - responseFutures[mid] = taskSource; - } + protected ValueTask WriteMessageWithResponseValueTaskAsync(int methodId, TRequest message) + { + ThrowIfDisposed(); + ThrowIfDisconnected(); - var v = BuildRequestMessage(methodId, mid, message); - if (!writerQueue.Writer.TryWrite(v)) - { - // If the channel writer is closed, it is likely that the connection has already been disconnected. - ThrowIfDisconnected(); - } + var mid = Interlocked.Increment(ref messageIdSequence); - return new ValueTask(taskSource, taskSource.Version); // wait until server return response(or error). if connection was closed, throws cancellation from DisposeAsyncCore. + var taskSource = StreamingHubResponseTaskSourcePool.Shared.RentOrCreate(); + lock (responseFutures) + { + responseFutures[mid] = taskSource; } - protected ValueTask WriteMessageWithResponseValueTaskAsync(int methodId, TRequest message) + var v = BuildRequestMessage(methodId, mid, message); + if (!writerQueue.Writer.TryWrite(v)) { - ThrowIfDisposed(); + // If the channel writer is closed, it is likely that the connection has already been disconnected. ThrowIfDisconnected(); + } - var mid = Interlocked.Increment(ref messageIdSequence); + return new ValueTask(taskSource, taskSource.Version); // wait until server return response(or error). if connection was closed, throws cancellation from DisposeAsyncCore. + } - var taskSource = StreamingHubResponseTaskSourcePool.Shared.RentOrCreate(); - lock (responseFutures) - { - responseFutures[mid] = taskSource; - } + protected void AwaitAndWriteClientResultResponseMessage(int methodId, Guid clientResultMessageId, Task task) + => AwaitAndWriteClientResultResponseMessage(methodId, clientResultMessageId, new ValueTask(task)); - var v = BuildRequestMessage(methodId, mid, message); - if (!writerQueue.Writer.TryWrite(v)) - { - // If the channel writer is closed, it is likely that the connection has already been disconnected. - ThrowIfDisconnected(); - } - - return new ValueTask(taskSource, taskSource.Version); // wait until server return response(or error). if connection was closed, throws cancellation from DisposeAsyncCore. + protected async void AwaitAndWriteClientResultResponseMessage(int methodId, Guid clientResultMessageId, ValueTask task) + { + try + { + await task.ConfigureAwait(false); + await WriteClientResultResponseMessageAsync(methodId, clientResultMessageId, MessagePack.Nil.Default).ConfigureAwait(false); } - - protected void AwaitAndWriteClientResultResponseMessage(int methodId, Guid clientResultMessageId, Task task) - => AwaitAndWriteClientResultResponseMessage(methodId, clientResultMessageId, new ValueTask(task)); - - protected async void AwaitAndWriteClientResultResponseMessage(int methodId, Guid clientResultMessageId, ValueTask task) + catch (Exception e) { - try - { - await task.ConfigureAwait(false); - await WriteClientResultResponseMessageAsync(methodId, clientResultMessageId, MessagePack.Nil.Default).ConfigureAwait(false); - } - catch (Exception e) - { - await WriteClientResultResponseMessageForErrorAsync(methodId, clientResultMessageId, e).ConfigureAwait(false); - } + await WriteClientResultResponseMessageForErrorAsync(methodId, clientResultMessageId, e).ConfigureAwait(false); } + } - protected void AwaitAndWriteClientResultResponseMessage(int methodId, Guid clientResultMessageId, Task task) - => AwaitAndWriteClientResultResponseMessage(methodId, clientResultMessageId, new ValueTask(task)); + protected void AwaitAndWriteClientResultResponseMessage(int methodId, Guid clientResultMessageId, Task task) + => AwaitAndWriteClientResultResponseMessage(methodId, clientResultMessageId, new ValueTask(task)); - protected async void AwaitAndWriteClientResultResponseMessage(int methodId, Guid clientResultMessageId, ValueTask task) + protected async void AwaitAndWriteClientResultResponseMessage(int methodId, Guid clientResultMessageId, ValueTask task) + { + try { - try - { - var result = await task.ConfigureAwait(false); - await WriteClientResultResponseMessageAsync(methodId, clientResultMessageId, result).ConfigureAwait(false); - } - catch (Exception e) - { - await WriteClientResultResponseMessageForErrorAsync(methodId, clientResultMessageId, e).ConfigureAwait(false); - } + var result = await task.ConfigureAwait(false); + await WriteClientResultResponseMessageAsync(methodId, clientResultMessageId, result).ConfigureAwait(false); } - - protected async void WriteClientResultResponseMessageForError(int methodId, Guid clientResultMessageId, Exception ex) + catch (Exception e) { - try - { - await WriteClientResultResponseMessageForErrorAsync(methodId, clientResultMessageId, ex).ConfigureAwait(false); - } - catch - { - // Ignore Exception - } + await WriteClientResultResponseMessageForErrorAsync(methodId, clientResultMessageId, e).ConfigureAwait(false); } + } - protected Task WriteClientResultResponseMessageAsync(int methodId, Guid clientResultMessageId, T result) + protected async void WriteClientResultResponseMessageForError(int methodId, Guid clientResultMessageId, Exception ex) + { + try { - var v = BuildClientResultResponseMessage(methodId, clientResultMessageId, result); - _ = writerQueue.Writer.TryWrite(v); - return Task.CompletedTask; + await WriteClientResultResponseMessageForErrorAsync(methodId, clientResultMessageId, ex).ConfigureAwait(false); } - - protected Task WriteClientResultResponseMessageForErrorAsync(int methodId, Guid clientResultMessageId, Exception ex) + catch { - var statusCode = ex is RpcException rpcException - ? rpcException.StatusCode - : StatusCode.Internal; + // Ignore Exception + } + } - var v = BuildClientResultResponseMessageForError(methodId, clientResultMessageId, (int)statusCode, ex.Message, ex); - _ = writerQueue.Writer.TryWrite(v); + protected Task WriteClientResultResponseMessageAsync(int methodId, Guid clientResultMessageId, T result) + { + var v = BuildClientResultResponseMessage(methodId, clientResultMessageId, result); + _ = writerQueue.Writer.TryWrite(v); + return Task.CompletedTask; + } - return Task.CompletedTask; - } + protected Task WriteClientResultResponseMessageForErrorAsync(int methodId, Guid clientResultMessageId, Exception ex) + { + var statusCode = ex is RpcException rpcException + ? rpcException.StatusCode + : StatusCode.Internal; - void ThrowIfDisconnected() + var v = BuildClientResultResponseMessageForError(methodId, clientResultMessageId, (int)statusCode, ex.Message, ex); + _ = writerQueue.Writer.TryWrite(v); + + return Task.CompletedTask; + } + + void ThrowIfDisconnected() + { + if (disconnected) { - if (disconnected) - { - throw new RpcException(new Status(StatusCode.Unavailable, $"The StreamingHubClient has already been disconnected from the server.")); - } + throw new RpcException(new Status(StatusCode.Unavailable, $"The StreamingHubClient has already been disconnected from the server.")); } + } - void ThrowIfDisposed() + void ThrowIfDisposed() + { + if (disposed) { - if (disposed) - { - throw new ObjectDisposedException("StreamingHubClient", $"The StreamingHubClient has already been disconnected from the server."); - } + throw new ObjectDisposedException("StreamingHubClient", $"The StreamingHubClient has already been disconnected from the server."); } + } + + public Task WaitForDisconnect() + => ((IStreamingHubClient)this).WaitForDisconnectAsync(); - public Task WaitForDisconnect() - => ((IStreamingHubClient)this).WaitForDisconnectAsync(); + Task IStreamingHubClient.WaitForDisconnectAsync() + => waitForDisconnect.Task; - Task IStreamingHubClient.WaitForDisconnectAsync() - => waitForDisconnect.Task; + public async Task DisposeAsync() + { + if (disposed) return; + disposed = true; + await CleanupAsync(true).ConfigureAwait(false); + } - public async Task DisposeAsync() + async ValueTask CleanupAsync(bool waitSubscription) + { + if (Interlocked.CompareExchange(ref cleanupSentinel, 1, 0) != 0) { - if (disposed) return; - disposed = true; - await CleanupAsync(true).ConfigureAwait(false); + return; } - async ValueTask CleanupAsync(bool waitSubscription) + if (writer == null) return; + try { - if (Interlocked.CompareExchange(ref cleanupSentinel, 1, 0) != 0) - { - return; - } - - if (writer == null) return; + writerQueue.Writer.Complete(); + await writer.CompleteAsync().ConfigureAwait(false); + } + catch { } // ignore error? + finally + { + subscriptionCts.Cancel(); try { - writerQueue.Writer.Complete(); - await writer.CompleteAsync().ConfigureAwait(false); - } - catch { } // ignore error? - finally - { - subscriptionCts.Cancel(); - try + if (waitSubscription) { - if (waitSubscription) + if (subscription != null) { - if (subscription != null) - { - await subscription.ConfigureAwait(false); - } + await subscription.ConfigureAwait(false); } + } - // cleanup completion - List? aggregateException = null; - foreach (var item in responseFutures) + // cleanup completion + List? aggregateException = null; + foreach (var item in responseFutures) + { + try { - try - { - (item.Value as IStreamingHubResponseTaskSource).TrySetCanceled(); - } - catch (Exception ex) - { - if (!(ex is OperationCanceledException)) - { - aggregateException ??= new List(); - aggregateException.Add(ex); - } - } + (item.Value as IStreamingHubResponseTaskSource).TrySetCanceled(); } - if (aggregateException != null) + catch (Exception ex) { - throw new AggregateException(aggregateException); + if (!(ex is OperationCanceledException)) + { + aggregateException ??= new List(); + aggregateException.Add(ex); + } } } - catch (Exception ex) + if (aggregateException != null) { - if (!(ex is OperationCanceledException)) - { - throw; - } + throw new AggregateException(aggregateException); + } + } + catch (Exception ex) + { + if (!(ex is OperationCanceledException)) + { + throw; } } - subscriptionCts.Dispose(); } + subscriptionCts.Dispose(); + } - StreamingHubPayload BuildRequestMessage(int methodId, T message) - { - using var buffer = ArrayPoolBufferWriter.RentThreadStaticWriter(); - StreamingHubMessageWriter.WriteRequestMessageVoid(buffer, methodId, message, messageSerializer); - return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.WrittenSpan); - } + StreamingHubPayload BuildRequestMessage(int methodId, T message) + { + using var buffer = ArrayPoolBufferWriter.RentThreadStaticWriter(); + StreamingHubMessageWriter.WriteRequestMessageVoid(buffer, methodId, message, messageSerializer); + return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.WrittenSpan); + } - StreamingHubPayload BuildRequestMessage(int methodId, int messageId, T message) - { - using var buffer = ArrayPoolBufferWriter.RentThreadStaticWriter(); - StreamingHubMessageWriter.WriteRequestMessage(buffer, methodId, messageId, message, messageSerializer); - return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.WrittenSpan); - } + StreamingHubPayload BuildRequestMessage(int methodId, int messageId, T message) + { + using var buffer = ArrayPoolBufferWriter.RentThreadStaticWriter(); + StreamingHubMessageWriter.WriteRequestMessage(buffer, methodId, messageId, message, messageSerializer); + return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.WrittenSpan); + } - StreamingHubPayload BuildClientResultResponseMessage(int methodId, Guid messageId, T response) - { - using var buffer = ArrayPoolBufferWriter.RentThreadStaticWriter(); - StreamingHubMessageWriter.WriteClientResultResponseMessage(buffer, methodId, messageId, response, messageSerializer); - return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.WrittenSpan); - } + StreamingHubPayload BuildClientResultResponseMessage(int methodId, Guid messageId, T response) + { + using var buffer = ArrayPoolBufferWriter.RentThreadStaticWriter(); + StreamingHubMessageWriter.WriteClientResultResponseMessage(buffer, methodId, messageId, response, messageSerializer); + return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.WrittenSpan); + } - StreamingHubPayload BuildClientResultResponseMessageForError(int methodId, Guid messageId, int statusCode, string detail, Exception? ex) - { - using var buffer = ArrayPoolBufferWriter.RentThreadStaticWriter(); - StreamingHubMessageWriter.WriteClientResultResponseMessageForError(buffer, methodId, messageId, statusCode, detail, ex, messageSerializer); - return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.WrittenSpan); - } + StreamingHubPayload BuildClientResultResponseMessageForError(int methodId, Guid messageId, int statusCode, string detail, Exception? ex) + { + using var buffer = ArrayPoolBufferWriter.RentThreadStaticWriter(); + StreamingHubMessageWriter.WriteClientResultResponseMessageForError(buffer, methodId, messageId, statusCode, detail, ex, messageSerializer); + return StreamingHubPayloadPool.Shared.RentOrCreate(buffer.WrittenSpan); } } diff --git a/src/MagicOnion.Client/StreamingHubClientExtensions.cs b/src/MagicOnion.Client/StreamingHubClientExtensions.cs index 9a74070d3..6fd0d0ad4 100644 --- a/src/MagicOnion.Client/StreamingHubClientExtensions.cs +++ b/src/MagicOnion.Client/StreamingHubClientExtensions.cs @@ -1,27 +1,26 @@ -namespace MagicOnion.Client +namespace MagicOnion.Client; + +public static class StreamingHubClientExtensions { - public static class StreamingHubClientExtensions - { - /// - /// Wait for the disconnection and return the reason. - /// - public static Task WaitForDisconnectAsync(this TStreamingHub hub) where TStreamingHub : IStreamingHubMarker => - CastOrThrow(hub).WaitForDisconnectAsync(); + /// + /// Wait for the disconnection and return the reason. + /// + public static Task WaitForDisconnectAsync(this TStreamingHub hub) where TStreamingHub : IStreamingHubMarker => + CastOrThrow(hub).WaitForDisconnectAsync(); - static IStreamingHubClient CastOrThrow(THub hub) + static IStreamingHubClient CastOrThrow(THub hub) + { + if (hub is null) + { + throw new ArgumentNullException(nameof(hub)); + } + if (hub is IStreamingHubClient client) + { + return client; + } + else { - if (hub is null) - { - throw new ArgumentNullException(nameof(hub)); - } - if (hub is IStreamingHubClient client) - { - return client; - } - else - { - throw new InvalidOperationException($"The StreamingHub client '{hub.GetType().FullName}' does not implement IStreamingHubClient interface."); - } + throw new InvalidOperationException($"The StreamingHub client '{hub.GetType().FullName}' does not implement IStreamingHubClient interface."); } } } diff --git a/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs b/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs index bf71e8cc5..8d9c7c2f8 100644 --- a/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs +++ b/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs @@ -2,72 +2,70 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -namespace MagicOnion.Client +namespace MagicOnion.Client; + +/// +/// Provides to get a StreamingHubClient factory of the specified service type. +/// +[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "ClientFactoryProvider is resolved at runtime.")] +public static class StreamingHubClientFactoryProvider { /// - /// Provides to get a StreamingHubClient factory of the specified service type. + /// Gets or set the StreamingHubClient factory provider to use by default. /// - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "ClientFactoryProvider is resolved at runtime.")] - public static class StreamingHubClientFactoryProvider - { - /// - /// Gets or set the StreamingHubClient factory provider to use by default. - /// - public static IStreamingHubClientFactoryProvider Default { get; set; } + public static IStreamingHubClientFactoryProvider Default { get; set; } #if NETSTANDARD2_0 = DynamicClient.DynamicStreamingHubClientFactoryProvider.Instance; #else - = RuntimeFeature.IsDynamicCodeSupported - ? DynamicClient.DynamicStreamingHubClientFactoryProvider.Instance - : DynamicClient.DynamicNotSupportedStreamingHubClientFactoryProvider.Instance; + = RuntimeFeature.IsDynamicCodeSupported + ? DynamicClient.DynamicStreamingHubClientFactoryProvider.Instance + : DynamicClient.DynamicNotSupportedStreamingHubClientFactoryProvider.Instance; #endif - } +} - public delegate TStreamingHub StreamingHubClientFactoryDelegate(TReceiver receiver, CallInvoker callInvoker, StreamingHubClientOptions options) - where TStreamingHub : IStreamingHub; +public delegate TStreamingHub StreamingHubClientFactoryDelegate(TReceiver receiver, CallInvoker callInvoker, StreamingHubClientOptions options) + where TStreamingHub : IStreamingHub; +/// +/// Provides to get a StreamingHubClient factory of the specified service type. +/// +public interface IStreamingHubClientFactoryProvider +{ /// - /// Provides to get a StreamingHubClient factory of the specified service type. + /// Gets the StreamingHubClient factory of the specified service type. A return value indicates whether a factory was found or not. /// - public interface IStreamingHubClientFactoryProvider + /// A MagicOnion StreamingHub interface type. + /// A hub receiver interface type. + /// A StreamingHubClient factory of specified service type. + /// The value indicates whether a factory was found or not. + bool TryGetFactory([NotNullWhen(true)] out StreamingHubClientFactoryDelegate? factory) where TStreamingHub : IStreamingHub; +} + +public class ImmutableStreamingHubClientFactoryProvider : IStreamingHubClientFactoryProvider +{ + readonly IStreamingHubClientFactoryProvider[] providers; + + public ImmutableStreamingHubClientFactoryProvider(params IStreamingHubClientFactoryProvider[] providers) { - /// - /// Gets the StreamingHubClient factory of the specified service type. A return value indicates whether a factory was found or not. - /// - /// A MagicOnion StreamingHub interface type. - /// A hub receiver interface type. - /// A StreamingHubClient factory of specified service type. - /// The value indicates whether a factory was found or not. - bool TryGetFactory([NotNullWhen(true)] out StreamingHubClientFactoryDelegate? factory) where TStreamingHub : IStreamingHub; + this.providers = providers; } - public class ImmutableStreamingHubClientFactoryProvider : IStreamingHubClientFactoryProvider + public ImmutableStreamingHubClientFactoryProvider Add(IStreamingHubClientFactoryProvider provider) { - readonly IStreamingHubClientFactoryProvider[] providers; - - public ImmutableStreamingHubClientFactoryProvider(params IStreamingHubClientFactoryProvider[] providers) - { - this.providers = providers; - } - - public ImmutableStreamingHubClientFactoryProvider Add(IStreamingHubClientFactoryProvider provider) - { - return new ImmutableStreamingHubClientFactoryProvider(providers.Append(provider).ToArray()); - } + return new ImmutableStreamingHubClientFactoryProvider(providers.Append(provider).ToArray()); + } - public bool TryGetFactory([NotNullWhen(true)] out StreamingHubClientFactoryDelegate? factory) where TStreamingHub : IStreamingHub + public bool TryGetFactory([NotNullWhen(true)] out StreamingHubClientFactoryDelegate? factory) where TStreamingHub : IStreamingHub + { + foreach (var provider in providers) { - foreach (var provider in providers) + if (provider.TryGetFactory(out factory)) { - if (provider.TryGetFactory(out factory)) - { - return true; - } + return true; } - - factory = default; - return false; } - } + factory = default; + return false; + } } diff --git a/src/MagicOnion.Internal/BroadcasterHelper.cs b/src/MagicOnion.Internal/BroadcasterHelper.cs index 57c294379..21c77860a 100644 --- a/src/MagicOnion.Internal/BroadcasterHelper.cs +++ b/src/MagicOnion.Internal/BroadcasterHelper.cs @@ -2,86 +2,85 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +[RequiresUnreferencedCode("BroadcastHelper is incompatible with trimming.")] +internal static class BroadcasterHelper { - [RequiresUnreferencedCode("BroadcastHelper is incompatible with trimming.")] - internal static class BroadcasterHelper + internal static Type[] DynamicArgumentTupleTypes { get; } = typeof(DynamicArgumentTuple<,>) + .GetTypeInfo() + .Assembly + .GetTypes() + .Where(x => x.Name.StartsWith("DynamicArgumentTuple") && !x.Name.Contains("Formatter")) + .OrderBy(x => x.GetGenericArguments().Length) + .ToArray(); + + internal static MethodDefinition[] SearchDefinitions(Type interfaceType) { - internal static Type[] DynamicArgumentTupleTypes { get; } = typeof(DynamicArgumentTuple<,>) - .GetTypeInfo() - .Assembly - .GetTypes() - .Where(x => x.Name.StartsWith("DynamicArgumentTuple") && !x.Name.Contains("Formatter")) - .OrderBy(x => x.GetGenericArguments().Length) - .ToArray(); + return interfaceType + .GetInterfaces() + .Concat(new[] { interfaceType }) + .SelectMany(x => x.GetMethods()) + .Where(x => + { + var methodInfo = x; + if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_"))) return false; + if (methodInfo.GetCustomAttribute(false) != null) return false; // ignore - internal static MethodDefinition[] SearchDefinitions(Type interfaceType) - { - return interfaceType - .GetInterfaces() - .Concat(new[] { interfaceType }) - .SelectMany(x => x.GetMethods()) - .Where(x => + var methodName = methodInfo.Name; + if (methodName == "Equals" + || methodName == "GetHashCode" + || methodName == "GetType" + || methodName == "ToString" + ) { - var methodInfo = x; - if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_"))) return false; - if (methodInfo.GetCustomAttribute(false) != null) return false; // ignore - - var methodName = methodInfo.Name; - if (methodName == "Equals" - || methodName == "GetHashCode" - || methodName == "GetType" - || methodName == "ToString" - ) - { - return false; - } + return false; + } - return true; - }) - .Where(x => !x.IsSpecialName) - .Select(x => new MethodDefinition(interfaceType, x, default)) - .ToArray(); - } + return true; + }) + .Where(x => !x.IsSpecialName) + .Select(x => new MethodDefinition(interfaceType, x, default)) + .ToArray(); + } - internal static void VerifyMethodDefinitions(MethodDefinition[] definitions) + internal static void VerifyMethodDefinitions(MethodDefinition[] definitions) + { + // define and set. + var map = new Dictionary(definitions.Length); + foreach (var item in definitions) { - // define and set. - var map = new Dictionary(definitions.Length); - foreach (var item in definitions) + var methodId = item.MethodInfo.GetCustomAttribute()?.MethodId ?? FNV1A32.GetHashCode(item.MethodInfo.Name); + if (map.ContainsKey(methodId)) { - var methodId = item.MethodInfo.GetCustomAttribute()?.MethodId ?? FNV1A32.GetHashCode(item.MethodInfo.Name); - if (map.ContainsKey(methodId)) - { - throw new Exception($"TReceiver does not allows duplicate methodId(hash code). Please change name or use MethodIdAttribute. {map[methodId].MethodInfo.Name} and {item.MethodInfo.Name}"); - } - map.Add(methodId, item); + throw new Exception($"TReceiver does not allows duplicate methodId(hash code). Please change name or use MethodIdAttribute. {map[methodId].MethodInfo.Name} and {item.MethodInfo.Name}"); + } + map.Add(methodId, item); - //if (!(item.MethodInfo.ReturnType == typeof(void))) - //{ - // throw new Exception($"Invalid definition, TReceiver's return type must only be `void`. {item.MethodInfo.Name}."); - //} + //if (!(item.MethodInfo.ReturnType == typeof(void))) + //{ + // throw new Exception($"Invalid definition, TReceiver's return type must only be `void`. {item.MethodInfo.Name}."); + //} - item.MethodId = methodId; - } + item.MethodId = methodId; } + } - internal class MethodDefinition - { - public string Path => ReceiverType.Name + "/" + MethodInfo.Name; + internal class MethodDefinition + { + public string Path => ReceiverType.Name + "/" + MethodInfo.Name; - public Type ReceiverType { get; set; } - public MethodInfo MethodInfo { get; set; } - public int MethodId { get; set; } - public bool IsClientResult { get; set; } + public Type ReceiverType { get; set; } + public MethodInfo MethodInfo { get; set; } + public int MethodId { get; set; } + public bool IsClientResult { get; set; } - public MethodDefinition(Type receiverType, MethodInfo methodInfo, int methodId) - { - ReceiverType = receiverType; - MethodInfo = methodInfo; - MethodId = methodId; - IsClientResult = methodInfo.ReturnType != typeof(void); - } + public MethodDefinition(Type receiverType, MethodInfo methodInfo, int methodId) + { + ReceiverType = receiverType; + MethodInfo = methodInfo; + MethodId = methodId; + IsClientResult = methodInfo.ReturnType != typeof(void); } } } diff --git a/src/MagicOnion.Internal/Buffers/ArrayPoolBufferWriter.cs b/src/MagicOnion.Internal/Buffers/ArrayPoolBufferWriter.cs index 6474f0350..a7e7d2888 100644 --- a/src/MagicOnion.Internal/Buffers/ArrayPoolBufferWriter.cs +++ b/src/MagicOnion.Internal/Buffers/ArrayPoolBufferWriter.cs @@ -1,113 +1,112 @@ using System.Buffers; using System.Diagnostics; -namespace MagicOnion.Internal.Buffers +namespace MagicOnion.Internal.Buffers; + +internal sealed class ArrayPoolBufferWriter : IBufferWriter, IDisposable { - internal sealed class ArrayPoolBufferWriter : IBufferWriter, IDisposable - { - [ThreadStatic] - static ArrayPoolBufferWriter? staticInstance; + [ThreadStatic] + static ArrayPoolBufferWriter? staticInstance; - public static ArrayPoolBufferWriter RentThreadStaticWriter() + public static ArrayPoolBufferWriter RentThreadStaticWriter() + { + if (staticInstance == null) { - if (staticInstance == null) - { - staticInstance = new ArrayPoolBufferWriter(); - } - staticInstance.Prepare(); + staticInstance = new ArrayPoolBufferWriter(); + } + staticInstance.Prepare(); #if DEBUG - var currentInstance = staticInstance; - staticInstance = null; - return currentInstance; + var currentInstance = staticInstance; + staticInstance = null; + return currentInstance; #else return staticInstance; #endif - } + } - const int MinimumBufferSize = 32767; // use 32k buffer. + const int MinimumBufferSize = 32767; // use 32k buffer. - byte[]? buffer; - int index; + byte[]? buffer; + int index; - void Prepare() + void Prepare() + { + if (buffer == null) { - if (buffer == null) - { - buffer = ArrayPool.Shared.Rent(MinimumBufferSize); - } - index = 0; + buffer = ArrayPool.Shared.Rent(MinimumBufferSize); } + index = 0; + } - public ReadOnlyMemory WrittenMemory => buffer.AsMemory(0, index); - public ReadOnlySpan WrittenSpan => buffer.AsSpan(0, index); + public ReadOnlyMemory WrittenMemory => buffer.AsMemory(0, index); + public ReadOnlySpan WrittenSpan => buffer.AsSpan(0, index); - public int WrittenCount => index; + public int WrittenCount => index; - public int Capacity => buffer?.Length ?? throw new ObjectDisposedException(nameof(ArrayPoolBufferWriter)); + public int Capacity => buffer?.Length ?? throw new ObjectDisposedException(nameof(ArrayPoolBufferWriter)); - public int FreeCapacity => Capacity - index; + public int FreeCapacity => Capacity - index; - public void Advance(int count) - { - if (count < 0) throw new ArgumentException(nameof(count)); - index += count; - } + public void Advance(int count) + { + if (count < 0) throw new ArgumentException(nameof(count)); + index += count; + } - public Memory GetMemory(int sizeHint = 0) - { - CheckAndResizeBuffer(sizeHint); - return buffer.AsMemory(index); - } + public Memory GetMemory(int sizeHint = 0) + { + CheckAndResizeBuffer(sizeHint); + return buffer.AsMemory(index); + } - public Span GetSpan(int sizeHint = 0) - { - CheckAndResizeBuffer(sizeHint); - return buffer.AsSpan(index); - } + public Span GetSpan(int sizeHint = 0) + { + CheckAndResizeBuffer(sizeHint); + return buffer.AsSpan(index); + } - void CheckAndResizeBuffer(int sizeHint) - { - if (buffer == null) throw new ObjectDisposedException(nameof(ArrayPoolBufferWriter)); - if (sizeHint < 0) throw new ArgumentException(nameof(sizeHint)); + void CheckAndResizeBuffer(int sizeHint) + { + if (buffer == null) throw new ObjectDisposedException(nameof(ArrayPoolBufferWriter)); + if (sizeHint < 0) throw new ArgumentException(nameof(sizeHint)); - if (sizeHint == 0) - { - sizeHint = MinimumBufferSize; - } + if (sizeHint == 0) + { + sizeHint = MinimumBufferSize; + } - int availableSpace = buffer.Length - index; + int availableSpace = buffer.Length - index; - if (sizeHint > availableSpace) - { - int growBy = Math.Max(sizeHint, buffer.Length); + if (sizeHint > availableSpace) + { + int growBy = Math.Max(sizeHint, buffer.Length); - int newSize = checked(buffer.Length + growBy); + int newSize = checked(buffer.Length + growBy); - byte[] oldBuffer = buffer; + byte[] oldBuffer = buffer; - buffer = ArrayPool.Shared.Rent(newSize); + buffer = ArrayPool.Shared.Rent(newSize); - Span previousBuffer = oldBuffer.AsSpan(0, index); - previousBuffer.CopyTo(buffer); - ArrayPool.Shared.Return(oldBuffer); - } + Span previousBuffer = oldBuffer.AsSpan(0, index); + previousBuffer.CopyTo(buffer); + ArrayPool.Shared.Return(oldBuffer); } + } - public void Dispose() + public void Dispose() + { + if (buffer == null) { - if (buffer == null) - { - return; - } + return; + } - ArrayPool.Shared.Return(buffer); - buffer = null; + ArrayPool.Shared.Return(buffer); + buffer = null; #if DEBUG - Debug.Assert(staticInstance is null); - staticInstance = this; + Debug.Assert(staticInstance is null); + staticInstance = this; #endif - } } } diff --git a/src/MagicOnion.Internal/DangerousDummyNull.cs b/src/MagicOnion.Internal/DangerousDummyNull.cs index d007b1384..6b7e47a5a 100644 --- a/src/MagicOnion.Internal/DangerousDummyNull.cs +++ b/src/MagicOnion.Internal/DangerousDummyNull.cs @@ -1,102 +1,100 @@ using System.Diagnostics; using System.Runtime.CompilerServices; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +/// +/// Provide a dummy Null object to cheat grpc-dotnet. +/// +/// +/// +/// Grpc.Net (grpc-dotnet) does not allow null values as messages. +/// However, gRPC does not need to know the contents of the message, and MagicOnion natively handles CLR objects. +/// so there is no problem if a null object is encountered between implementation and serialization. +/// +/// +/// See: https://github.com/grpc/grpc-dotnet/blob/51ec4d05e6b38532c959018728277f2477cc6a7e/src/Grpc.AspNetCore.Server/Internal/CallHandlers/UnaryServerCallHandler.cs#L52-L56 +/// +/// +/// grpc-dotnet also does not care about the message content, +/// MagicOnion will replace the null value with a singleton-dummy `System.Object` instance as `T` by `Unsafe.As`. +/// When serializing or deserializing a request/response, it will replace the dummy object back to `null` or with a dummy object. +/// +/// +/// +/// - Request (on server): +/// [MagicOnion Client] +/// | +/// | (MessagePack binary) +/// | +/// [ASP.NET Core gRPC server (grpc-dotnet)] +/// | +/// [MessageSerializer.Deserialize<T> (MagicOnion)] +/// | +/// | (object or null) +/// | +/// [DangerousDummyNull.GetObjectOrDummyNull (MagicOnion)] +/// | +/// | (object or DummyNull) +/// | +/// [CallHandler (grpc-dotnet)] +/// | +/// [DangerousDummyNull.GetObjectOrDefault (MagicOnion)] +/// | +/// | (object or null) +/// | +/// [Unary method (User-code)] +/// +/// +/// - Response (on server): +/// [Unary method (User-code)] +/// | +/// | (object or null) +/// | +/// [DangerousDummyNull.GetObjectOrDummyNull (MagicOnion)] +/// | +/// | (object or DummyNull) +/// | +/// [CallHandler (grpc-dotnet)] +/// | +/// [DangerousDummyNull.GetObjectOrDefault (MagicOnion)] +/// | +/// | (object or null) +/// | +/// [MessageSerializer.Serialize<T> (MagicOnion)] +/// | +/// | (MessagePack binary) +/// | +/// [ASP.NET Core gRPC server (grpc-dotnet)] +/// | +/// [MagicOnion Client] +/// +internal class DangerousDummyNull { - /// - /// Provide a dummy Null object to cheat grpc-dotnet. - /// - /// - /// - /// Grpc.Net (grpc-dotnet) does not allow null values as messages. - /// However, gRPC does not need to know the contents of the message, and MagicOnion natively handles CLR objects. - /// so there is no problem if a null object is encountered between implementation and serialization. - /// - /// - /// See: https://github.com/grpc/grpc-dotnet/blob/51ec4d05e6b38532c959018728277f2477cc6a7e/src/Grpc.AspNetCore.Server/Internal/CallHandlers/UnaryServerCallHandler.cs#L52-L56 - /// - /// - /// grpc-dotnet also does not care about the message content, - /// MagicOnion will replace the null value with a singleton-dummy `System.Object` instance as `T` by `Unsafe.As`. - /// When serializing or deserializing a request/response, it will replace the dummy object back to `null` or with a dummy object. - /// - /// - /// - /// - Request (on server): - /// [MagicOnion Client] - /// | - /// | (MessagePack binary) - /// | - /// [ASP.NET Core gRPC server (grpc-dotnet)] - /// | - /// [MessageSerializer.Deserialize<T> (MagicOnion)] - /// | - /// | (object or null) - /// | - /// [DangerousDummyNull.GetObjectOrDummyNull (MagicOnion)] - /// | - /// | (object or DummyNull) - /// | - /// [CallHandler (grpc-dotnet)] - /// | - /// [DangerousDummyNull.GetObjectOrDefault (MagicOnion)] - /// | - /// | (object or null) - /// | - /// [Unary method (User-code)] - /// - /// - /// - Response (on server): - /// [Unary method (User-code)] - /// | - /// | (object or null) - /// | - /// [DangerousDummyNull.GetObjectOrDummyNull (MagicOnion)] - /// | - /// | (object or DummyNull) - /// | - /// [CallHandler (grpc-dotnet)] - /// | - /// [DangerousDummyNull.GetObjectOrDefault (MagicOnion)] - /// | - /// | (object or null) - /// | - /// [MessageSerializer.Serialize<T> (MagicOnion)] - /// | - /// | (MessagePack binary) - /// | - /// [ASP.NET Core gRPC server (grpc-dotnet)] - /// | - /// [MagicOnion Client] - /// - internal class DangerousDummyNull - { - public static DangerousDummyNull Instance { get; } = new DangerousDummyNull(); + public static DangerousDummyNull Instance { get; } = new DangerousDummyNull(); - DangerousDummyNull() - {} + DangerousDummyNull() + {} - public static T GetObjectOrDummyNull(T value) + public static T GetObjectOrDummyNull(T value) + { + if (value is null) { - if (value is null) - { - Debug.Assert(typeof(T).IsClass); - var instance = Instance; - return Unsafe.As(ref instance); - } - - return value; + Debug.Assert(typeof(T).IsClass); + var instance = Instance; + return Unsafe.As(ref instance); } - public static T GetObjectOrDefault(object value) - { - if (object.ReferenceEquals(value, Instance)) - { - return default(T)!; - } + return value; + } - return (T)value; + public static T GetObjectOrDefault(object value) + { + if (object.ReferenceEquals(value, Instance)) + { + return default(T)!; } + + return (T)value; } } - diff --git a/src/MagicOnion.Internal/FNV1A32.cs b/src/MagicOnion.Internal/FNV1A32.cs index d9209ea8a..7ec8651df 100644 --- a/src/MagicOnion.Internal/FNV1A32.cs +++ b/src/MagicOnion.Internal/FNV1A32.cs @@ -1,27 +1,26 @@ using System.Text; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +internal static class FNV1A32 { - internal static class FNV1A32 + public static int GetHashCode(string str) { - public static int GetHashCode(string str) - { - return GetHashCode(Encoding.UTF8.GetBytes(str)); - } + return GetHashCode(Encoding.UTF8.GetBytes(str)); + } - public static int GetHashCode(byte[] obj) + public static int GetHashCode(byte[] obj) + { + uint hash = 0; + if (obj != null) { - uint hash = 0; - if (obj != null) + hash = 2166136261; + for (int i = 0; i < obj.Length; i++) { - hash = 2166136261; - for (int i = 0; i < obj.Length; i++) - { - hash = unchecked((obj[i] ^ hash) * 16777619); - } + hash = unchecked((obj[i] ^ hash) * 16777619); } - - return unchecked((int)hash); } + + return unchecked((int)hash); } } diff --git a/src/MagicOnion.Internal/GrpcMethodHelper.cs b/src/MagicOnion.Internal/GrpcMethodHelper.cs index cb959516a..acbc6406b 100644 --- a/src/MagicOnion.Internal/GrpcMethodHelper.cs +++ b/src/MagicOnion.Internal/GrpcMethodHelper.cs @@ -3,131 +3,130 @@ using MagicOnion.Serialization; using MessagePack; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +internal static class GrpcMethodHelper { - internal static class GrpcMethodHelper - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TRaw ToRaw(T obj) - => (obj is ValueType) - ? (TRaw)(object)Box.Create(obj) - : DangerousDummyNull.GetObjectOrDummyNull(Unsafe.As(ref obj)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TRaw ToRaw(T obj) + => (obj is ValueType) + ? (TRaw)(object)Box.Create(obj) + : DangerousDummyNull.GetObjectOrDummyNull(Unsafe.As(ref obj)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T FromRaw(TRaw obj) - => (obj is Box boxed) - ? boxed.Value - : DangerousDummyNull.GetObjectOrDefault(obj!); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T FromRaw(TRaw obj) + => (obj is Box boxed) + ? boxed.Value + : DangerousDummyNull.GetObjectOrDefault(obj!); - public static Method, TRawResponse> CreateMethod(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer) - where TRawResponse : class - { - // WORKAROUND: Prior to MagicOnion 5.0, the request type for the parameter-less method was byte[]. - // DynamicClient sends byte[], but GeneratedClient sends Nil, which is incompatible, - // so as a special case we do not serialize/deserialize and always convert to a fixed values. - var isMethodResponseTypeBoxed = typeof(TResponse).IsValueType; - var responseMarshaller = isMethodResponseTypeBoxed - ? CreateBoxedMarshaller(messageSerializer) - : (object)CreateMarshaller(messageSerializer); + public static Method, TRawResponse> CreateMethod(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer) + where TRawResponse : class + { + // WORKAROUND: Prior to MagicOnion 5.0, the request type for the parameter-less method was byte[]. + // DynamicClient sends byte[], but GeneratedClient sends Nil, which is incompatible, + // so as a special case we do not serialize/deserialize and always convert to a fixed values. + var isMethodResponseTypeBoxed = typeof(TResponse).IsValueType; + var responseMarshaller = isMethodResponseTypeBoxed + ? CreateBoxedMarshaller(messageSerializer) + : (object)CreateMarshaller(messageSerializer); - return new Method, TRawResponse>( - methodType, - serviceName, - name, - IgnoreNilMarshaller, - (Marshaller)responseMarshaller - ); - } + return new Method, TRawResponse>( + methodType, + serviceName, + name, + IgnoreNilMarshaller, + (Marshaller)responseMarshaller + ); + } - public static Method CreateMethod(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer) - where TRawRequest : class - where TRawResponse : class - { - var isMethodRequestTypeBoxed = typeof(TRequest).IsValueType; - var isMethodResponseTypeBoxed = typeof(TResponse).IsValueType; + public static Method CreateMethod(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer) + where TRawRequest : class + where TRawResponse : class + { + var isMethodRequestTypeBoxed = typeof(TRequest).IsValueType; + var isMethodResponseTypeBoxed = typeof(TResponse).IsValueType; - var requestMarshaller = isMethodRequestTypeBoxed - ? CreateBoxedMarshaller(messageSerializer) - : (object)CreateMarshaller(messageSerializer); - var responseMarshaller = isMethodResponseTypeBoxed - ? CreateBoxedMarshaller(messageSerializer) - : (object)CreateMarshaller(messageSerializer); + var requestMarshaller = isMethodRequestTypeBoxed + ? CreateBoxedMarshaller(messageSerializer) + : (object)CreateMarshaller(messageSerializer); + var responseMarshaller = isMethodResponseTypeBoxed + ? CreateBoxedMarshaller(messageSerializer) + : (object)CreateMarshaller(messageSerializer); - return new Method( - methodType, - serviceName, - name, - (Marshaller)requestMarshaller, - (Marshaller)responseMarshaller - ); - } + return new Method( + methodType, + serviceName, + name, + (Marshaller)requestMarshaller, + (Marshaller)responseMarshaller + ); + } - // WORKAROUND: Prior to MagicOnion 5.0, the request type for the parameter-less method was byte[]. - // DynamicClient sends byte[], but GeneratedClient sends Nil, which is incompatible, - // so as a special case we do not serialize/deserialize and always convert to a fixed values. - public static Marshaller> IgnoreNilMarshaller { get; } = new Marshaller>( - serializer: (obj, ctx) => - { - ReadOnlySpan unsafeNilBytes = new[] { MessagePackCode.Nil }; + // WORKAROUND: Prior to MagicOnion 5.0, the request type for the parameter-less method was byte[]. + // DynamicClient sends byte[], but GeneratedClient sends Nil, which is incompatible, + // so as a special case we do not serialize/deserialize and always convert to a fixed values. + public static Marshaller> IgnoreNilMarshaller { get; } = new Marshaller>( + serializer: (obj, ctx) => + { + ReadOnlySpan unsafeNilBytes = new[] { MessagePackCode.Nil }; - var writer = ctx.GetBufferWriter(); - var buffer = writer.GetSpan(unsafeNilBytes.Length); // Write `Nil` as `byte[]` to the buffer. - unsafeNilBytes.CopyTo(buffer); - writer.Advance(unsafeNilBytes.Length); + var writer = ctx.GetBufferWriter(); + var buffer = writer.GetSpan(unsafeNilBytes.Length); // Write `Nil` as `byte[]` to the buffer. + unsafeNilBytes.CopyTo(buffer); + writer.Advance(unsafeNilBytes.Length); - ctx.Complete(); - }, - deserializer: (ctx) => Box.Create(Nil.Default) /* Box.Create always returns cached Box */ - ); + ctx.Complete(); + }, + deserializer: (ctx) => Box.Create(Nil.Default) /* Box.Create always returns cached Box */ + ); - static Marshaller CreateMarshaller(IMagicOnionSerializer messageSerializer) - { - return new Marshaller( - serializer: (obj, ctx) => - { + static Marshaller CreateMarshaller(IMagicOnionSerializer messageSerializer) + { + return new Marshaller( + serializer: (obj, ctx) => + { #pragma warning disable CS8602 - if (obj.GetType() == typeof(RawBytesBox)) + if (obj.GetType() == typeof(RawBytesBox)) #pragma warning restore CS8602 - { - var rawBytesBox = (RawBytesBox)(object)obj; - var writer = ctx.GetBufferWriter(); - var buffer = writer.GetSpan(rawBytesBox.Bytes.Length); - rawBytesBox.Bytes.Span.CopyTo(buffer); - writer.Advance(rawBytesBox.Bytes.Length); - } - else - { - messageSerializer.Serialize(ctx.GetBufferWriter(), DangerousDummyNull.GetObjectOrDefault(obj)); - } - ctx.Complete(); - }, - deserializer: (ctx) => DangerousDummyNull.GetObjectOrDummyNull(messageSerializer.Deserialize(ctx.PayloadAsReadOnlySequence()))!); - } - - static Marshaller> CreateBoxedMarshaller(IMagicOnionSerializer messageSerializer) - { - return new Marshaller>( - serializer: (obj, ctx) => { + var rawBytesBox = (RawBytesBox)(object)obj; + var writer = ctx.GetBufferWriter(); + var buffer = writer.GetSpan(rawBytesBox.Bytes.Length); + rawBytesBox.Bytes.Span.CopyTo(buffer); + writer.Advance(rawBytesBox.Bytes.Length); + } + else + { + messageSerializer.Serialize(ctx.GetBufferWriter(), DangerousDummyNull.GetObjectOrDefault(obj)); + } + ctx.Complete(); + }, + deserializer: (ctx) => DangerousDummyNull.GetObjectOrDummyNull(messageSerializer.Deserialize(ctx.PayloadAsReadOnlySequence()))!); + } + + static Marshaller> CreateBoxedMarshaller(IMagicOnionSerializer messageSerializer) + { + return new Marshaller>( + serializer: (obj, ctx) => + { #pragma warning disable CS8602 - if (obj.GetType() == typeof(RawBytesBox)) + if (obj.GetType() == typeof(RawBytesBox)) #pragma warning restore CS8602 - { - var rawBytesBox = (RawBytesBox)(object)obj; - var writer = ctx.GetBufferWriter(); - var buffer = writer.GetSpan(rawBytesBox.Bytes.Length); - rawBytesBox.Bytes.Span.CopyTo(buffer); - writer.Advance(rawBytesBox.Bytes.Length); - } - else - { - messageSerializer.Serialize(ctx.GetBufferWriter(), obj.Value); - } - ctx.Complete(); - }, - deserializer: (ctx) => Box.Create(messageSerializer.Deserialize(ctx.PayloadAsReadOnlySequence())!) - ); - } - + { + var rawBytesBox = (RawBytesBox)(object)obj; + var writer = ctx.GetBufferWriter(); + var buffer = writer.GetSpan(rawBytesBox.Bytes.Length); + rawBytesBox.Bytes.Span.CopyTo(buffer); + writer.Advance(rawBytesBox.Bytes.Length); + } + else + { + messageSerializer.Serialize(ctx.GetBufferWriter(), obj.Value); + } + ctx.Complete(); + }, + deserializer: (ctx) => Box.Create(messageSerializer.Deserialize(ctx.PayloadAsReadOnlySequence())!) + ); } + } diff --git a/src/MagicOnion.Internal/MagicOnionAsyncStreamReader.cs b/src/MagicOnion.Internal/MagicOnionAsyncStreamReader.cs index ba8e4c038..7feaa6734 100644 --- a/src/MagicOnion.Internal/MagicOnionAsyncStreamReader.cs +++ b/src/MagicOnion.Internal/MagicOnionAsyncStreamReader.cs @@ -1,20 +1,19 @@ using Grpc.Core; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +internal class MagicOnionAsyncStreamReader : IAsyncStreamReader { - internal class MagicOnionAsyncStreamReader : IAsyncStreamReader - { - readonly IAsyncStreamReader inner; + readonly IAsyncStreamReader inner; - public MagicOnionAsyncStreamReader(IAsyncStreamReader inner) - { - this.inner = inner; - } + public MagicOnionAsyncStreamReader(IAsyncStreamReader inner) + { + this.inner = inner; + } - public Task MoveNext(CancellationToken cancellationToken) - => inner.MoveNext(cancellationToken); + public Task MoveNext(CancellationToken cancellationToken) + => inner.MoveNext(cancellationToken); - public T Current - => GrpcMethodHelper.FromRaw(inner.Current); - } + public T Current + => GrpcMethodHelper.FromRaw(inner.Current); } diff --git a/src/MagicOnion.Internal/MagicOnionClientStreamWriter.cs b/src/MagicOnion.Internal/MagicOnionClientStreamWriter.cs index b95d4f079..e84ef51ec 100644 --- a/src/MagicOnion.Internal/MagicOnionClientStreamWriter.cs +++ b/src/MagicOnion.Internal/MagicOnionClientStreamWriter.cs @@ -1,25 +1,24 @@ using Grpc.Core; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +internal class MagicOnionClientStreamWriter : IClientStreamWriter { - internal class MagicOnionClientStreamWriter : IClientStreamWriter - { - readonly IClientStreamWriter inner; + readonly IClientStreamWriter inner; - public MagicOnionClientStreamWriter(IClientStreamWriter inner) - { - this.inner = inner; - } + public MagicOnionClientStreamWriter(IClientStreamWriter inner) + { + this.inner = inner; + } - public Task WriteAsync(T message) - => inner.WriteAsync(GrpcMethodHelper.ToRaw(message)); + public Task WriteAsync(T message) + => inner.WriteAsync(GrpcMethodHelper.ToRaw(message)); - public WriteOptions? WriteOptions - { - get => inner.WriteOptions; - set => inner.WriteOptions = value; - } - public Task CompleteAsync() - => inner.CompleteAsync(); + public WriteOptions? WriteOptions + { + get => inner.WriteOptions; + set => inner.WriteOptions = value; } + public Task CompleteAsync() + => inner.CompleteAsync(); } diff --git a/src/MagicOnion.Internal/MagicOnionMarshallers.cs b/src/MagicOnion.Internal/MagicOnionMarshallers.cs index 6cb349f7c..d872c1a6c 100644 --- a/src/MagicOnion.Internal/MagicOnionMarshallers.cs +++ b/src/MagicOnion.Internal/MagicOnionMarshallers.cs @@ -3,69 +3,67 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; -namespace MagicOnion.Internal -{ - // invoke from dynamic methods so must be public - internal static class MagicOnionMarshallers - { - public static Marshaller StreamingHubMarshaller { get; } = new( - serializer: static (payload, context) => - { - context.SetPayloadLength(payload.Length); - var bufferWriter = context.GetBufferWriter(); - payload.Span.CopyTo(bufferWriter.GetSpan(payload.Length)); - bufferWriter.Advance(payload.Length); - context.Complete(); - StreamingHubPayloadPool.Shared.Return(payload); - }, - deserializer: static context => - { - return StreamingHubPayloadPool.Shared.RentOrCreate(context.PayloadAsReadOnlySequence()); - } - ); +namespace MagicOnion.Internal; - [RequiresUnreferencedCode(nameof(MagicOnionMarshallers) + "." + nameof(CreateRequestType) + " is incompatible with trimming and Native AOT.")] - public static Type CreateRequestType(ParameterInfo[] parameters) +// invoke from dynamic methods so must be public +internal static class MagicOnionMarshallers +{ + public static Marshaller StreamingHubMarshaller { get; } = new( + serializer: static (payload, context) => { - if (parameters.Length == 0) - { - return typeof(Nil); - } - else if (parameters.Length == 1) - { - var t = parameters[0].ParameterType; - return t; - } - else if (parameters.Length >= 16) - { - throw new InvalidOperationException($"The method '{parameters[0].Member.DeclaringType!.FullName}.{parameters[0].Member.Name}' must have less than 16 parameters. (Length: {parameters.Length})"); - } - else - { - // start from T2 - var tupleTypeBase = DynamicArgumentTupleTypesCache.Types[parameters.Length - 2]; - var t = tupleTypeBase.MakeGenericType(parameters.Select(x => x.ParameterType).ToArray()); - return t; - } + context.SetPayloadLength(payload.Length); + var bufferWriter = context.GetBufferWriter(); + payload.Span.CopyTo(bufferWriter.GetSpan(payload.Length)); + bufferWriter.Advance(payload.Length); + context.Complete(); + StreamingHubPayloadPool.Shared.Return(payload); + }, + deserializer: static context => + { + return StreamingHubPayloadPool.Shared.RentOrCreate(context.PayloadAsReadOnlySequence()); } + ); - [RequiresUnreferencedCode(nameof(MagicOnionMarshallers) + "." + nameof(InstantiateDynamicArgumentTuple) + " is incompatible with trimming and Native AOT.")] - public static object InstantiateDynamicArgumentTuple(Type[] typeParameters, object[] arguments) + [RequiresUnreferencedCode(nameof(MagicOnionMarshallers) + "." + nameof(CreateRequestType) + " is incompatible with trimming and Native AOT.")] + public static Type CreateRequestType(ParameterInfo[] parameters) + { + if (parameters.Length == 0) { - // start from T2 - var tupleTypeBase = DynamicArgumentTupleTypesCache.Types[arguments.Length - 2]; - return Activator.CreateInstance(tupleTypeBase.MakeGenericType(typeParameters), arguments)!; + return typeof(Nil); } - - [RequiresUnreferencedCode(nameof(DynamicArgumentTupleTypesCache) + " is incompatible with trimming and Native AOT.")] - static class DynamicArgumentTupleTypesCache + else if (parameters.Length == 1) + { + var t = parameters[0].ParameterType; + return t; + } + else if (parameters.Length >= 16) { - public static readonly Type[] Types = typeof(DynamicArgumentTuple<,>).GetTypeInfo().Assembly - .GetTypes() - .Where(x => x.Name.StartsWith("DynamicArgumentTuple") && !x.Name.Contains("Formatter")) - .OrderBy(x => x.GetGenericArguments().Length) - .ToArray(); + throw new InvalidOperationException($"The method '{parameters[0].Member.DeclaringType!.FullName}.{parameters[0].Member.Name}' must have less than 16 parameters. (Length: {parameters.Length})"); } + else + { + // start from T2 + var tupleTypeBase = DynamicArgumentTupleTypesCache.Types[parameters.Length - 2]; + var t = tupleTypeBase.MakeGenericType(parameters.Select(x => x.ParameterType).ToArray()); + return t; + } + } + + [RequiresUnreferencedCode(nameof(MagicOnionMarshallers) + "." + nameof(InstantiateDynamicArgumentTuple) + " is incompatible with trimming and Native AOT.")] + public static object InstantiateDynamicArgumentTuple(Type[] typeParameters, object[] arguments) + { + // start from T2 + var tupleTypeBase = DynamicArgumentTupleTypesCache.Types[arguments.Length - 2]; + return Activator.CreateInstance(tupleTypeBase.MakeGenericType(typeParameters), arguments)!; } + [RequiresUnreferencedCode(nameof(DynamicArgumentTupleTypesCache) + " is incompatible with trimming and Native AOT.")] + static class DynamicArgumentTupleTypesCache + { + public static readonly Type[] Types = typeof(DynamicArgumentTuple<,>).GetTypeInfo().Assembly + .GetTypes() + .Where(x => x.Name.StartsWith("DynamicArgumentTuple") && !x.Name.Contains("Formatter")) + .OrderBy(x => x.GetGenericArguments().Length) + .ToArray(); + } } diff --git a/src/MagicOnion.Internal/MagicOnionServerStreamWriter.cs b/src/MagicOnion.Internal/MagicOnionServerStreamWriter.cs index 6c6fd1c78..73c2ec028 100644 --- a/src/MagicOnion.Internal/MagicOnionServerStreamWriter.cs +++ b/src/MagicOnion.Internal/MagicOnionServerStreamWriter.cs @@ -1,23 +1,22 @@ using Grpc.Core; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +internal class MagicOnionServerStreamWriter : IServerStreamWriter { - internal class MagicOnionServerStreamWriter : IServerStreamWriter - { - readonly IServerStreamWriter inner; + readonly IServerStreamWriter inner; - public MagicOnionServerStreamWriter(IServerStreamWriter inner) - { - this.inner = inner; - } + public MagicOnionServerStreamWriter(IServerStreamWriter inner) + { + this.inner = inner; + } - public Task WriteAsync(T message) - => inner.WriteAsync(GrpcMethodHelper.ToRaw(message)); + public Task WriteAsync(T message) + => inner.WriteAsync(GrpcMethodHelper.ToRaw(message)); - public WriteOptions? WriteOptions - { - get => inner.WriteOptions; - set => inner.WriteOptions = value; - } + public WriteOptions? WriteOptions + { + get => inner.WriteOptions; + set => inner.WriteOptions = value; } } diff --git a/src/MagicOnion.Internal/Polyfil/RequiresUnreferencedCodeAttribute.cs b/src/MagicOnion.Internal/Polyfil/RequiresUnreferencedCodeAttribute.cs index a59a86c95..988e38ebf 100644 --- a/src/MagicOnion.Internal/Polyfil/RequiresUnreferencedCodeAttribute.cs +++ b/src/MagicOnion.Internal/Polyfil/RequiresUnreferencedCodeAttribute.cs @@ -1,20 +1,15 @@ #if !NET6_0_OR_GREATER -using System; -using System.Collections.Generic; -using System.Text; +namespace System.Diagnostics.CodeAnalysis; -namespace System.Diagnostics.CodeAnalysis +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)] +internal class RequiresUnreferencedCodeAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)] - internal class RequiresUnreferencedCodeAttribute : Attribute - { - public string Message { get; } - public string? Url { get; } + public string Message { get; } + public string? Url { get; } - public RequiresUnreferencedCodeAttribute(string message) - { - Message = message; - } + public RequiresUnreferencedCodeAttribute(string message) + { + Message = message; } } #endif diff --git a/src/MagicOnion.Internal/Polyfil/UnconditionalSuppressMessageAttribute.cs b/src/MagicOnion.Internal/Polyfil/UnconditionalSuppressMessageAttribute.cs index 4e5dff129..d0fedd329 100644 --- a/src/MagicOnion.Internal/Polyfil/UnconditionalSuppressMessageAttribute.cs +++ b/src/MagicOnion.Internal/Polyfil/UnconditionalSuppressMessageAttribute.cs @@ -1,25 +1,20 @@ #if !NET6_0_OR_GREATER -using System; -using System.Collections.Generic; -using System.Text; +namespace System.Diagnostics.CodeAnalysis; -namespace System.Diagnostics.CodeAnalysis +[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] +internal class UnconditionalSuppressMessageAttribute : Attribute { - [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] - internal class UnconditionalSuppressMessageAttribute : Attribute - { - public string Category { get; } - public string CheckId { get; } - public string? Scope { get; set; } - public string? Target { get; set; } - public string? Justification { get; set; } - public string? MessageId { get; set; } + public string Category { get; } + public string CheckId { get; } + public string? Scope { get; set; } + public string? Target { get; set; } + public string? Justification { get; set; } + public string? MessageId { get; set; } - public UnconditionalSuppressMessageAttribute(string category, string checkId) - { - Category = category; - CheckId = checkId; - } + public UnconditionalSuppressMessageAttribute(string category, string checkId) + { + Category = category; + CheckId = checkId; } } #endif diff --git a/src/MagicOnion.Internal/Reflection/ILGeneratorExtensions.cs b/src/MagicOnion.Internal/Reflection/ILGeneratorExtensions.cs index effaca280..b3c93b681 100644 --- a/src/MagicOnion.Internal/Reflection/ILGeneratorExtensions.cs +++ b/src/MagicOnion.Internal/Reflection/ILGeneratorExtensions.cs @@ -1,164 +1,163 @@ using System.Reflection.Emit; -namespace MagicOnion.Internal.Reflection -{ - // full list of can create optimize helper -> https://github.com/kevin-montrose/Sigil#automated-opcode-choice +namespace MagicOnion.Internal.Reflection; + +// full list of can create optimize helper -> https://github.com/kevin-montrose/Sigil#automated-opcode-choice +/// +/// Provides optimized generation code and helpers. +/// +internal static class ILGeneratorExtensions +{ /// - /// Provides optimized generation code and helpers. + /// Loads the local variable at a specific index onto the evaluation stack. /// - internal static class ILGeneratorExtensions + public static void EmitLdloc(this ILGenerator il, int index) { - /// - /// Loads the local variable at a specific index onto the evaluation stack. - /// - public static void EmitLdloc(this ILGenerator il, int index) + switch (index) { - switch (index) - { - case 0: - il.Emit(OpCodes.Ldloc_0); - break; - case 1: - il.Emit(OpCodes.Ldloc_1); - break; - case 2: - il.Emit(OpCodes.Ldloc_2); - break; - case 3: - il.Emit(OpCodes.Ldloc_3); - break; - default: - if (index <= 255) - { - il.Emit(OpCodes.Ldloc_S, (byte)index); - } - else - { - il.Emit(OpCodes.Ldloc, (short)index); - } - break; - } + case 0: + il.Emit(OpCodes.Ldloc_0); + break; + case 1: + il.Emit(OpCodes.Ldloc_1); + break; + case 2: + il.Emit(OpCodes.Ldloc_2); + break; + case 3: + il.Emit(OpCodes.Ldloc_3); + break; + default: + if (index <= 255) + { + il.Emit(OpCodes.Ldloc_S, (byte)index); + } + else + { + il.Emit(OpCodes.Ldloc, (short)index); + } + break; } + } - /// - /// Pops the current value from the top of the evaluation stack and stores it in a the local variable list at a specified index. - /// - public static void EmitStloc(this ILGenerator il, int index) + /// + /// Pops the current value from the top of the evaluation stack and stores it in a the local variable list at a specified index. + /// + public static void EmitStloc(this ILGenerator il, int index) + { + switch (index) { - switch (index) - { - case 0: - il.Emit(OpCodes.Stloc_0); - break; - case 1: - il.Emit(OpCodes.Stloc_1); - break; - case 2: - il.Emit(OpCodes.Stloc_2); - break; - case 3: - il.Emit(OpCodes.Stloc_3); - break; - default: - if (index <= 255) - { - il.Emit(OpCodes.Stloc_S, (byte)index); - } - else - { - il.Emit(OpCodes.Stloc, (short)index); - } - break; - } + case 0: + il.Emit(OpCodes.Stloc_0); + break; + case 1: + il.Emit(OpCodes.Stloc_1); + break; + case 2: + il.Emit(OpCodes.Stloc_2); + break; + case 3: + il.Emit(OpCodes.Stloc_3); + break; + default: + if (index <= 255) + { + il.Emit(OpCodes.Stloc_S, (byte)index); + } + else + { + il.Emit(OpCodes.Stloc, (short)index); + } + break; } + } - /// - /// Loads the address of the local variable at a specific index onto the evaluation statck. - /// - public static void EmitLdloca(this ILGenerator il, int index) + /// + /// Loads the address of the local variable at a specific index onto the evaluation statck. + /// + public static void EmitLdloca(this ILGenerator il, int index) + { + if (index <= 255) { - if (index <= 255) - { - il.Emit(OpCodes.Ldloca_S, (byte)index); - } - else - { - il.Emit(OpCodes.Ldloca, (short)index); - } + il.Emit(OpCodes.Ldloca_S, (byte)index); } - - /// - /// Pushes a supplied value of type int32 onto the evaluation stack as an int32. - /// - public static void EmitLdc_I4(this ILGenerator il, int value) + else { - switch (value) - { - case -1: - il.Emit(OpCodes.Ldc_I4_M1); - break; - case 0: - il.Emit(OpCodes.Ldc_I4_0); - break; - case 1: - il.Emit(OpCodes.Ldc_I4_1); - break; - case 2: - il.Emit(OpCodes.Ldc_I4_2); - break; - case 3: - il.Emit(OpCodes.Ldc_I4_3); - break; - case 4: - il.Emit(OpCodes.Ldc_I4_4); - break; - case 5: - il.Emit(OpCodes.Ldc_I4_5); - break; - case 6: - il.Emit(OpCodes.Ldc_I4_6); - break; - case 7: - il.Emit(OpCodes.Ldc_I4_7); - break; - case 8: - il.Emit(OpCodes.Ldc_I4_8); - break; - default: - if (value >= -128 && value <= 127) - { - il.Emit(OpCodes.Ldc_I4_S, (sbyte)value); - } - else - { - il.Emit(OpCodes.Ldc_I4, value); - } - break; - } + il.Emit(OpCodes.Ldloca, (short)index); } + } - /// - /// Helper for Pop op. - /// - public static void EmitPop(this ILGenerator il, int count) + /// + /// Pushes a supplied value of type int32 onto the evaluation stack as an int32. + /// + public static void EmitLdc_I4(this ILGenerator il, int value) + { + switch (value) { - for (int i = 0; i < count; i++) - { - il.Emit(OpCodes.Pop); - } + case -1: + il.Emit(OpCodes.Ldc_I4_M1); + break; + case 0: + il.Emit(OpCodes.Ldc_I4_0); + break; + case 1: + il.Emit(OpCodes.Ldc_I4_1); + break; + case 2: + il.Emit(OpCodes.Ldc_I4_2); + break; + case 3: + il.Emit(OpCodes.Ldc_I4_3); + break; + case 4: + il.Emit(OpCodes.Ldc_I4_4); + break; + case 5: + il.Emit(OpCodes.Ldc_I4_5); + break; + case 6: + il.Emit(OpCodes.Ldc_I4_6); + break; + case 7: + il.Emit(OpCodes.Ldc_I4_7); + break; + case 8: + il.Emit(OpCodes.Ldc_I4_8); + break; + default: + if (value >= -128 && value <= 127) + { + il.Emit(OpCodes.Ldc_I4_S, (sbyte)value); + } + else + { + il.Emit(OpCodes.Ldc_I4, value); + } + break; } + } - public static void EmitNullReturn(this ILGenerator il) + /// + /// Helper for Pop op. + /// + public static void EmitPop(this ILGenerator il, int count) + { + for (int i = 0; i < count; i++) { - il.Emit(OpCodes.Ldnull); - il.Emit(OpCodes.Ret); + il.Emit(OpCodes.Pop); } + } - public static void EmitThrowNotimplemented(this ILGenerator il) - { - il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(Type.EmptyTypes)!); - il.Emit(OpCodes.Throw); - } + public static void EmitNullReturn(this ILGenerator il) + { + il.Emit(OpCodes.Ldnull); + il.Emit(OpCodes.Ret); + } + + public static void EmitThrowNotimplemented(this ILGenerator il) + { + il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(Type.EmptyTypes)!); + il.Emit(OpCodes.Throw); } } diff --git a/src/MagicOnion.Internal/StreamingHubClientMessageReader.cs b/src/MagicOnion.Internal/StreamingHubClientMessageReader.cs index 2cbb566d3..da42f7328 100644 --- a/src/MagicOnion.Internal/StreamingHubClientMessageReader.cs +++ b/src/MagicOnion.Internal/StreamingHubClientMessageReader.cs @@ -1,119 +1,118 @@ using MessagePack; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +internal ref struct StreamingHubClientMessageReader { - internal ref struct StreamingHubClientMessageReader - { - readonly ReadOnlyMemory data; - int position; + readonly ReadOnlyMemory data; + int position; - public StreamingHubClientMessageReader(ReadOnlyMemory data) - { - this.data = data; - this.position = 0; - } - void VerifyResultAndAdvance(MessagePackPrimitives.DecodeResult result, int readLen) + public StreamingHubClientMessageReader(ReadOnlyMemory data) + { + this.data = data; + this.position = 0; + } + void VerifyResultAndAdvance(MessagePackPrimitives.DecodeResult result, int readLen) + { + if (result != MessagePackPrimitives.DecodeResult.Success) { - if (result != MessagePackPrimitives.DecodeResult.Success) - { - throw new InvalidOperationException($"Invalid message format: {result}"); - } - position += readLen; + throw new InvalidOperationException($"Invalid message format: {result}"); } + position += readLen; + } - public StreamingHubMessageType ReadMessageType() + public StreamingHubMessageType ReadMessageType() + { + VerifyResultAndAdvance(MessagePackPrimitives.TryReadArrayHeader(data.Span.Slice(position), out var arrayLength, out var read), read); + return arrayLength switch { - VerifyResultAndAdvance(MessagePackPrimitives.TryReadArrayHeader(data.Span.Slice(position), out var arrayLength, out var read), read); - return arrayLength switch - { - 2 => StreamingHubMessageType.Broadcast, - 3 => StreamingHubMessageType.Response, - 4 => StreamingHubMessageType.ResponseWithError, - 5 => ReadMessageSubType(), - _ => throw new InvalidOperationException($"Unknown message format: ArrayLength = {arrayLength}"), - }; - } + 2 => StreamingHubMessageType.Broadcast, + 3 => StreamingHubMessageType.Response, + 4 => StreamingHubMessageType.ResponseWithError, + 5 => ReadMessageSubType(), + _ => throw new InvalidOperationException($"Unknown message format: ArrayLength = {arrayLength}"), + }; + } - StreamingHubMessageType ReadMessageSubType() + StreamingHubMessageType ReadMessageSubType() + { + VerifyResultAndAdvance(MessagePackPrimitives.TryReadByte(data.Span.Slice(position), out var subType, out var read), read); + return subType switch { - VerifyResultAndAdvance(MessagePackPrimitives.TryReadByte(data.Span.Slice(position), out var subType, out var read), read); - return subType switch - { - 0x00 /* 0:ClientResultRequest */ => StreamingHubMessageType.ClientResultRequest, - 0x7e /* 126:ClientHeartbeatResponse */ => StreamingHubMessageType.ClientHeartbeatResponse, - 0x7f /* 127:ServerHeartbeat */ => StreamingHubMessageType.ServerHeartbeat, - _ => throw new InvalidOperationException($"Unknown Type: {subType}"), - }; - } + 0x00 /* 0:ClientResultRequest */ => StreamingHubMessageType.ClientResultRequest, + 0x7e /* 126:ClientHeartbeatResponse */ => StreamingHubMessageType.ClientHeartbeatResponse, + 0x7f /* 127:ServerHeartbeat */ => StreamingHubMessageType.ServerHeartbeat, + _ => throw new InvalidOperationException($"Unknown Type: {subType}"), + }; + } - public (int MethodId, int Cosumed) ReadBroadcastMessageMethodId() - { - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var methodId, out var readMethodId), readMethodId); - return (methodId, position); - } + public (int MethodId, int Cosumed) ReadBroadcastMessageMethodId() + { + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var methodId, out var readMethodId), readMethodId); + return (methodId, position); + } - public (int MethodId, ReadOnlyMemory Body) ReadBroadcastMessage() - { - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var methodId, out var readMethodId), readMethodId); - return (methodId, data.Slice(position)); - } + public (int MethodId, ReadOnlyMemory Body) ReadBroadcastMessage() + { + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var methodId, out var readMethodId), readMethodId); + return (methodId, data.Slice(position)); + } - public (int MessageId, int MethodId, ReadOnlyMemory Body) ReadResponseMessage() - { - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var messageId, out var readMessageId), readMessageId); - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var methodId, out var readMethodId), readMethodId); - return (messageId, methodId, data.Slice(position)); - } + public (int MessageId, int MethodId, ReadOnlyMemory Body) ReadResponseMessage() + { + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var messageId, out var readMessageId), readMessageId); + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var methodId, out var readMethodId), readMethodId); + return (messageId, methodId, data.Slice(position)); + } - public (int MessageId, int StatusCode, string? Detail, string? Error) ReadResponseWithErrorMessage() - { - var reader = new MessagePackReader(data.Slice(position)); - var messageId = reader.ReadInt32(); - var statusCode = reader.ReadInt32(); - var detail = reader.ReadString(); - var error = reader.ReadString(); + public (int MessageId, int StatusCode, string? Detail, string? Error) ReadResponseWithErrorMessage() + { + var reader = new MessagePackReader(data.Slice(position)); + var messageId = reader.ReadInt32(); + var statusCode = reader.ReadInt32(); + var detail = reader.ReadString(); + var error = reader.ReadString(); - return (messageId, statusCode, detail, error); - } + return (messageId, statusCode, detail, error); + } - public (Guid ClientResultRequestMessageId, int MethodId, ReadOnlyMemory Body) ReadClientResultRequestMessage() - { - var reader = new MessagePackReader(data.Slice(position)); - //var type = reader.ReadByte(); // Type is already read by ReadMessageType - reader.Skip(); // Dummy - var clientRequestMessageId = MessagePackSerializer.Deserialize(ref reader); - var methodId = reader.ReadInt32(); - position += (int)reader.Consumed; - - return (clientRequestMessageId, methodId, data.Slice(position)); - } + public (Guid ClientResultRequestMessageId, int MethodId, ReadOnlyMemory Body) ReadClientResultRequestMessage() + { + var reader = new MessagePackReader(data.Slice(position)); + //var type = reader.ReadByte(); // Type is already read by ReadMessageType + reader.Skip(); // Dummy + var clientRequestMessageId = MessagePackSerializer.Deserialize(ref reader); + var methodId = reader.ReadInt32(); + position += (int)reader.Consumed; + + return (clientRequestMessageId, methodId, data.Slice(position)); + } - public (short Sequence, long ServerSentAt, ReadOnlyMemory Metadata) ReadServerHeartbeat() - { - // Type is already read by ReadMessageType (Byte) + public (short Sequence, long ServerSentAt, ReadOnlyMemory Metadata) ReadServerHeartbeat() + { + // Type is already read by ReadMessageType (Byte) - // Sequence (1) - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt16(data.Span.Slice(position), out var sequence, out var readLenSequence), readLenSequence); - // ServerSentAt (2) - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt64(data.Span.Slice(position), out var serverSentAt, out var readLenServerSentAt), readLenServerSentAt); - // Reserved (3) - VerifyResultAndAdvance(MessagePackPrimitives.TryReadNil(data.Span.Slice(position), out var readLenReserved), readLenReserved); + // Sequence (1) + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt16(data.Span.Slice(position), out var sequence, out var readLenSequence), readLenSequence); + // ServerSentAt (2) + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt64(data.Span.Slice(position), out var serverSentAt, out var readLenServerSentAt), readLenServerSentAt); + // Reserved (3) + VerifyResultAndAdvance(MessagePackPrimitives.TryReadNil(data.Span.Slice(position), out var readLenReserved), readLenReserved); - return (sequence, serverSentAt, data.Slice(position)); - } + return (sequence, serverSentAt, data.Slice(position)); + } - public (short Sequence, long ClientSentAt) ReadClientHeartbeatResponse() - { - // Type is already read by ReadMessageType (Byte) + public (short Sequence, long ClientSentAt) ReadClientHeartbeatResponse() + { + // Type is already read by ReadMessageType (Byte) - // Sequence (1) - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt16(data.Span.Slice(position), out var sequence, out var readLenSequence), readLenSequence); - // ClientSentAt (2) - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt64(data.Span.Slice(position), out var clientSentAt, out var readLenClientSentAt), readLenClientSentAt); - // Reserved (3) - VerifyResultAndAdvance(MessagePackPrimitives.TryReadNil(data.Span.Slice(position), out var readLenReserved), readLenReserved); + // Sequence (1) + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt16(data.Span.Slice(position), out var sequence, out var readLenSequence), readLenSequence); + // ClientSentAt (2) + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt64(data.Span.Slice(position), out var clientSentAt, out var readLenClientSentAt), readLenClientSentAt); + // Reserved (3) + VerifyResultAndAdvance(MessagePackPrimitives.TryReadNil(data.Span.Slice(position), out var readLenReserved), readLenReserved); - return (sequence, clientSentAt); - } + return (sequence, clientSentAt); } } diff --git a/src/MagicOnion.Internal/StreamingHubMessageWriter.cs b/src/MagicOnion.Internal/StreamingHubMessageWriter.cs index 1bac680b0..49ddffc7e 100644 --- a/src/MagicOnion.Internal/StreamingHubMessageWriter.cs +++ b/src/MagicOnion.Internal/StreamingHubMessageWriter.cs @@ -4,373 +4,372 @@ using MagicOnion.Serialization; using MessagePack; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +/// +/// StreamingHub message formats (from Server to Client): +/// +/// +/// Response: InvokeHubMethod (from server to client) +/// Array(3): [MessageId(int), MethodId(int), SerializedResponse] +/// +/// +/// Response: InvokeHubMethod (from server to client; with Exception) +/// Array(4): [MessageId(int), StatusCode(int), Detail(string), Message(string)] +/// +/// +/// Broadcast: from server to client +/// Array(2): [MethodId(int), SerializedArgument] +/// +/// +/// ClientInvoke/Request: InvokeClientMethod (from server to client) +/// Array(5): [Type=0x00, Nil, ClientResultMessageId(Guid), MethodId(int), SerializedArguments] +/// +/// +/// ServerHeartbeat/Request: +/// Array(5): [Type=0x7f, Nil, Nil, Nil, Extras] +/// +/// +/// ClientHeartbeat/Response: +/// Array(5): [Type=0x7e, Nil, Nil, Nil, [ClientTime(long)]] +/// +/// +/// StreamingHub message formats (from Client to Server): +/// +/// +/// Request: InvokeHubMethod (from client; void; fire-and-forget) +/// Array(2): [MethodId(int), SerializedArguments] +/// +/// +/// Request: InvokeHubMethod (from client; non-void) +/// Array(3): [MessageId(int), MethodId(int), SerializedArguments] +/// +/// +/// ClientInvoke/Response: InvokeClientMethod (from client to server) +/// Array(4): [Type=0x00, ClientResultMessageId(Guid), MethodId(int), SerializedResponse] +/// +/// +/// ClientInvoke/Response: InvokeClientMethod (from client to server; with Exception) +/// Array(4): [Type=0x01, ClientResultMessageId(Guid), MethodId(int), [StatusCode(int), Detail(string), Message(string)]] +/// +/// +/// ServerHeartbeat/Response: +/// Array(4): [Type=0x7f, Nil, Nil, Nil] +/// +/// +/// ClientHeartbeat/Request: +/// Array(4): [Type=0x7e, Nil, Nil, [ClientTime(long)]] +/// +/// +/// +internal static class StreamingHubMessageWriter { - /// - /// StreamingHub message formats (from Server to Client): - /// - /// - /// Response: InvokeHubMethod (from server to client) - /// Array(3): [MessageId(int), MethodId(int), SerializedResponse] - /// - /// - /// Response: InvokeHubMethod (from server to client; with Exception) - /// Array(4): [MessageId(int), StatusCode(int), Detail(string), Message(string)] - /// - /// - /// Broadcast: from server to client - /// Array(2): [MethodId(int), SerializedArgument] - /// - /// - /// ClientInvoke/Request: InvokeClientMethod (from server to client) - /// Array(5): [Type=0x00, Nil, ClientResultMessageId(Guid), MethodId(int), SerializedArguments] - /// - /// - /// ServerHeartbeat/Request: - /// Array(5): [Type=0x7f, Nil, Nil, Nil, Extras] - /// - /// - /// ClientHeartbeat/Response: - /// Array(5): [Type=0x7e, Nil, Nil, Nil, [ClientTime(long)]] - /// - /// - /// StreamingHub message formats (from Client to Server): - /// - /// - /// Request: InvokeHubMethod (from client; void; fire-and-forget) - /// Array(2): [MethodId(int), SerializedArguments] - /// - /// - /// Request: InvokeHubMethod (from client; non-void) - /// Array(3): [MessageId(int), MethodId(int), SerializedArguments] - /// - /// - /// ClientInvoke/Response: InvokeClientMethod (from client to server) - /// Array(4): [Type=0x00, ClientResultMessageId(Guid), MethodId(int), SerializedResponse] - /// - /// - /// ClientInvoke/Response: InvokeClientMethod (from client to server; with Exception) - /// Array(4): [Type=0x01, ClientResultMessageId(Guid), MethodId(int), [StatusCode(int), Detail(string), Message(string)]] - /// - /// - /// ServerHeartbeat/Response: - /// Array(4): [Type=0x7f, Nil, Nil, Nil] - /// - /// - /// ClientHeartbeat/Request: - /// Array(4): [Type=0x7e, Nil, Nil, [ClientTime(long)]] - /// - /// - /// - internal static class StreamingHubMessageWriter + /// + /// Writes a broadcast message of Hub method. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteBroadcastMessage(IBufferWriter bufferWriter, int methodId, T value, IMagicOnionSerializer messageSerializer) { - /// - /// Writes a broadcast message of Hub method. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteBroadcastMessage(IBufferWriter bufferWriter, int methodId, T value, IMagicOnionSerializer messageSerializer) - { - var bytesWritten = 0; - var written = 0; - Span header = bufferWriter.GetSpan(16); - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(header.Slice(bytesWritten), 2, out written), written, ref bytesWritten); - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), methodId, out written), written, ref bytesWritten); - bufferWriter.Advance(bytesWritten); - - messageSerializer.Serialize(bufferWriter, value); - } + var bytesWritten = 0; + var written = 0; + Span header = bufferWriter.GetSpan(16); + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(header.Slice(bytesWritten), 2, out written), written, ref bytesWritten); + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), methodId, out written), written, ref bytesWritten); + bufferWriter.Advance(bytesWritten); + + messageSerializer.Serialize(bufferWriter, value); + } - /// - /// Writes a request message of Hub method. - /// - public static void WriteRequestMessageVoid(IBufferWriter bufferWriter, int methodId, T value, IMagicOnionSerializer messageSerializer) - { - var bytesWritten = 0; - var written = 0; - Span header = bufferWriter.GetSpan(16); - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(header.Slice(bytesWritten), 2, out written), written, ref bytesWritten); - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), methodId, out written), written, ref bytesWritten); - bufferWriter.Advance(bytesWritten); - - messageSerializer.Serialize(bufferWriter, value); - } + /// + /// Writes a request message of Hub method. + /// + public static void WriteRequestMessageVoid(IBufferWriter bufferWriter, int methodId, T value, IMagicOnionSerializer messageSerializer) + { + var bytesWritten = 0; + var written = 0; + Span header = bufferWriter.GetSpan(16); + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(header.Slice(bytesWritten), 2, out written), written, ref bytesWritten); + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), methodId, out written), written, ref bytesWritten); + bufferWriter.Advance(bytesWritten); + + messageSerializer.Serialize(bufferWriter, value); + } - /// - /// Writes a request message of Hub method. - /// - public static void WriteRequestMessage(IBufferWriter bufferWriter, int methodId, int messageId, T value, IMagicOnionSerializer messageSerializer) - { - var bytesWritten = 0; - var written = 0; - Span header = bufferWriter.GetSpan(16); - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(header.Slice(bytesWritten), 3, out written), written, ref bytesWritten); - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), messageId, out written), written, ref bytesWritten); - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), methodId, out written), written, ref bytesWritten); - bufferWriter.Advance(bytesWritten); - - messageSerializer.Serialize(bufferWriter, value); - } + /// + /// Writes a request message of Hub method. + /// + public static void WriteRequestMessage(IBufferWriter bufferWriter, int methodId, int messageId, T value, IMagicOnionSerializer messageSerializer) + { + var bytesWritten = 0; + var written = 0; + Span header = bufferWriter.GetSpan(16); + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(header.Slice(bytesWritten), 3, out written), written, ref bytesWritten); + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), messageId, out written), written, ref bytesWritten); + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), methodId, out written), written, ref bytesWritten); + bufferWriter.Advance(bytesWritten); + + messageSerializer.Serialize(bufferWriter, value); + } - /// - /// Writes an empty response message of Hub method. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteResponseMessage(IBufferWriter bufferWriter, int methodId, int messageId) - { - var bytesWritten = 0; - var written = 0; - Span header = bufferWriter.GetSpan(16); - - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(header.Slice(bytesWritten), 3, out written), written, ref bytesWritten); - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), messageId, out written), written, ref bytesWritten); - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), methodId, out written), written, ref bytesWritten); - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(header.Slice(bytesWritten), out written), written, ref bytesWritten); - bufferWriter.Advance(bytesWritten); - } + /// + /// Writes an empty response message of Hub method. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteResponseMessage(IBufferWriter bufferWriter, int methodId, int messageId) + { + var bytesWritten = 0; + var written = 0; + Span header = bufferWriter.GetSpan(16); + + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(header.Slice(bytesWritten), 3, out written), written, ref bytesWritten); + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), messageId, out written), written, ref bytesWritten); + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), methodId, out written), written, ref bytesWritten); + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(header.Slice(bytesWritten), out written), written, ref bytesWritten); + bufferWriter.Advance(bytesWritten); + } - /// - /// Writes a response message of Hub method. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteResponseMessage(IBufferWriter bufferWriter, int methodId, int messageId, T v, IMagicOnionSerializer messageSerializer) - { - var bytesWritten = 0; - var written = 0; - Span header = bufferWriter.GetSpan(16); - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(header.Slice(bytesWritten), 3, out written), written, ref bytesWritten); - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), messageId, out written), written, ref bytesWritten); - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), methodId, out written), written, ref bytesWritten); - bufferWriter.Advance(bytesWritten); - - messageSerializer.Serialize(bufferWriter, v); - } + /// + /// Writes a response message of Hub method. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteResponseMessage(IBufferWriter bufferWriter, int methodId, int messageId, T v, IMagicOnionSerializer messageSerializer) + { + var bytesWritten = 0; + var written = 0; + Span header = bufferWriter.GetSpan(16); + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(header.Slice(bytesWritten), 3, out written), written, ref bytesWritten); + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), messageId, out written), written, ref bytesWritten); + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(header.Slice(bytesWritten), methodId, out written), written, ref bytesWritten); + bufferWriter.Advance(bytesWritten); + + messageSerializer.Serialize(bufferWriter, v); + } - /// - /// Write an error response message of Hub method. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteResponseMessageForError(IBufferWriter bufferWriter, int messageId, int statusCode, string detail, Exception? ex, bool isReturnExceptionStackTraceInErrorDetail) - { - var writer = new MessagePackWriter(bufferWriter); - writer.WriteArrayHeader(4); - writer.Write(messageId); - writer.Write(statusCode); - writer.Write(detail); + /// + /// Write an error response message of Hub method. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteResponseMessageForError(IBufferWriter bufferWriter, int messageId, int statusCode, string detail, Exception? ex, bool isReturnExceptionStackTraceInErrorDetail) + { + var writer = new MessagePackWriter(bufferWriter); + writer.WriteArrayHeader(4); + writer.Write(messageId); + writer.Write(statusCode); + writer.Write(detail); + + var msg = (isReturnExceptionStackTraceInErrorDetail && ex != null) + ? ex.ToString() + : null; + + writer.Write(msg); + writer.Flush(); + } - var msg = (isReturnExceptionStackTraceInErrorDetail && ex != null) - ? ex.ToString() - : null; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteClientResultRequestMessage(IBufferWriter bufferWriter, int methodId, Guid messageId, T request, IMagicOnionSerializer messageSerializer) + { + var writer = new MessagePackWriter(bufferWriter); + writer.WriteArrayHeader(5); + writer.Write(0); // Type = ClientResultRequest (0) + writer.WriteNil(); // Dummy + MessagePackSerializer.Serialize(ref writer, messageId); + writer.Write(methodId); + writer.Flush(); + messageSerializer.Serialize(bufferWriter, request); + } - writer.Write(msg); - writer.Flush(); - } + /// + /// Writes a response message for client result. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteClientResultResponseMessage(IBufferWriter bufferWriter, int methodId, Guid messageId, T response, IMagicOnionSerializer messageSerializer) + { + var writer = new MessagePackWriter(bufferWriter); + writer.WriteArrayHeader(4); + writer.Write(0); // Result = 0 (success) + MessagePackSerializer.Serialize(ref writer, messageId); + writer.Write(methodId); + writer.Flush(); + messageSerializer.Serialize(bufferWriter, response); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteClientResultRequestMessage(IBufferWriter bufferWriter, int methodId, Guid messageId, T request, IMagicOnionSerializer messageSerializer) - { - var writer = new MessagePackWriter(bufferWriter); - writer.WriteArrayHeader(5); - writer.Write(0); // Type = ClientResultRequest (0) - writer.WriteNil(); // Dummy - MessagePackSerializer.Serialize(ref writer, messageId); - writer.Write(methodId); - writer.Flush(); - messageSerializer.Serialize(bufferWriter, request); - } + /// + /// Writes an error response message for client result. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteClientResultResponseMessageForError(IBufferWriter bufferWriter, int methodId, Guid messageId, int statusCode, string detail, Exception? ex, IMagicOnionSerializer messageSerializer) + { + var writer = new MessagePackWriter(bufferWriter); + writer.WriteArrayHeader(4); + writer.Write(1); // Result = 1 (failed) + MessagePackSerializer.Serialize(ref writer, messageId); + writer.Write(methodId); - /// - /// Writes a response message for client result. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteClientResultResponseMessage(IBufferWriter bufferWriter, int methodId, Guid messageId, T response, IMagicOnionSerializer messageSerializer) + writer.WriteArrayHeader(3); { - var writer = new MessagePackWriter(bufferWriter); - writer.WriteArrayHeader(4); - writer.Write(0); // Result = 0 (success) - MessagePackSerializer.Serialize(ref writer, messageId); - writer.Write(methodId); - writer.Flush(); - messageSerializer.Serialize(bufferWriter, response); + writer.Write(statusCode); + writer.Write(detail); + writer.Write(ex?.ToString()); } + writer.Flush(); + } - /// - /// Writes an error response message for client result. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteClientResultResponseMessageForError(IBufferWriter bufferWriter, int methodId, Guid messageId, int statusCode, string detail, Exception? ex, IMagicOnionSerializer messageSerializer) - { - var writer = new MessagePackWriter(bufferWriter); - writer.WriteArrayHeader(4); - writer.Write(1); // Result = 1 (failed) - MessagePackSerializer.Serialize(ref writer, messageId); - writer.Write(methodId); - - writer.WriteArrayHeader(3); - { - writer.Write(statusCode); - writer.Write(detail); - writer.Write(ex?.ToString()); - } - writer.Flush(); - } + /// + /// Writes a server heartbeat message for sending from the server. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteServerHeartbeatMessageHeader(IBufferWriter bufferWriter, short sequence, DateTimeOffset serverSentAt) + { + var written = 0; + var bytesWritten = 0; + var buffer = bufferWriter.GetSpan(32); + + // Array(5)[127, Sequence(int8), ServerSentAt(long; UnixTimeMs), Nil, ] + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(buffer.Slice(bytesWritten), 5, out written), written, ref bytesWritten); + // Type = 0x7f / 127 (Heartbeat) + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), 0x7f, out written), written, ref bytesWritten); + // 1:Sequence + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), sequence, out written), written, ref bytesWritten); + // 2:ServerSentAt + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), serverSentAt.ToUnixTimeMilliseconds(), out written), written, ref bytesWritten); + // 3:Reserved (Nil) + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(buffer.Slice(bytesWritten), out written), written, ref bytesWritten); + + bufferWriter.Advance(bytesWritten); + } - /// - /// Writes a server heartbeat message for sending from the server. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteServerHeartbeatMessageHeader(IBufferWriter bufferWriter, short sequence, DateTimeOffset serverSentAt) - { - var written = 0; - var bytesWritten = 0; - var buffer = bufferWriter.GetSpan(32); - - // Array(5)[127, Sequence(int8), ServerSentAt(long; UnixTimeMs), Nil, ] - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(buffer.Slice(bytesWritten), 5, out written), written, ref bytesWritten); - // Type = 0x7f / 127 (Heartbeat) - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), 0x7f, out written), written, ref bytesWritten); - // 1:Sequence - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), sequence, out written), written, ref bytesWritten); - // 2:ServerSentAt - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), serverSentAt.ToUnixTimeMilliseconds(), out written), written, ref bytesWritten); - // 3:Reserved (Nil) - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(buffer.Slice(bytesWritten), out written), written, ref bytesWritten); - - bufferWriter.Advance(bytesWritten); - } + /// + /// Writes a server heartbeat message for sending response from the client. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteServerHeartbeatMessageResponse(Span buffer, short sequence, long serverSentAt, out int bytesWritten) + { + Debug.Assert(buffer.Length >= 5 + 5 + 5 + 5 + 9); + var written = bytesWritten = 0; + + // Array(4)[127, Sequence(int8), ServerSentAt(long; UnixTimeMs), Nil] + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(buffer.Slice(bytesWritten), 4, out written), written, ref bytesWritten); + // Type = 0x7f / 127 (Heartbeat) + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), 0x7f, out written), written, ref bytesWritten); + // 1:Sequence + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), sequence, out written), written, ref bytesWritten); + // 2:ServerSentAt + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), serverSentAt, out written), written, ref bytesWritten); + // 3:Reserved (Nil) + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(buffer.Slice(bytesWritten), out written), written, ref bytesWritten); + } - /// - /// Writes a server heartbeat message for sending response from the client. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteServerHeartbeatMessageResponse(Span buffer, short sequence, long serverSentAt, out int bytesWritten) - { - Debug.Assert(buffer.Length >= 5 + 5 + 5 + 5 + 9); - var written = bytesWritten = 0; - - // Array(4)[127, Sequence(int8), ServerSentAt(long; UnixTimeMs), Nil] - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(buffer.Slice(bytesWritten), 4, out written), written, ref bytesWritten); - // Type = 0x7f / 127 (Heartbeat) - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), 0x7f, out written), written, ref bytesWritten); - // 1:Sequence - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), sequence, out written), written, ref bytesWritten); - // 2:ServerSentAt - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), serverSentAt, out written), written, ref bytesWritten); - // 3:Reserved (Nil) - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(buffer.Slice(bytesWritten), out written), written, ref bytesWritten); - } + /// + /// Writes a client heartbeat message for sending from the client. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteClientHeartbeatMessage(Span buffer, short sequence, long clientSentAtElapsedFromOriginMs, out int bytesWritten) + { + Debug.Assert(buffer.Length >= 5 + 5 + 5 + 5 + 9); + var written = bytesWritten = 0; + + // Array(4)[0x7e(126), Sequence(int8), ClientSentAtElapsedFromOrigin(long; Ms), ] + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(buffer.Slice(bytesWritten), 4, out written), written, ref bytesWritten); + // 0:Type = 0x7e / 126 (ClientHeartbeat) + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), 0x7e, out written), written, ref bytesWritten); + // 1:Sequence + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), sequence, out written), written, ref bytesWritten); + // 2:ClientSentAtElapsedFromOrigin + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), clientSentAtElapsedFromOriginMs, out written), written, ref bytesWritten); + // 3:Reserved (Nil) + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(buffer.Slice(bytesWritten), out written), written, ref bytesWritten); + } - /// - /// Writes a client heartbeat message for sending from the client. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteClientHeartbeatMessage(Span buffer, short sequence, long clientSentAtElapsedFromOriginMs, out int bytesWritten) - { - Debug.Assert(buffer.Length >= 5 + 5 + 5 + 5 + 9); - var written = bytesWritten = 0; - - // Array(4)[0x7e(126), Sequence(int8), ClientSentAtElapsedFromOrigin(long; Ms), ] - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(buffer.Slice(bytesWritten), 4, out written), written, ref bytesWritten); - // 0:Type = 0x7e / 126 (ClientHeartbeat) - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), 0x7e, out written), written, ref bytesWritten); - // 1:Sequence - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), sequence, out written), written, ref bytesWritten); - // 2:ClientSentAtElapsedFromOrigin - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), clientSentAtElapsedFromOriginMs, out written), written, ref bytesWritten); - // 3:Reserved (Nil) - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(buffer.Slice(bytesWritten), out written), written, ref bytesWritten); - } + /// + /// Writes a client heartbeat message for sending response from the server. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteClientHeartbeatMessageResponse(IBufferWriter bufferWriter, short sequence, long clientSentAt) + { + var written = 0; + var bytesWritten = 0; + var buffer = bufferWriter.GetSpan(32); + + // Array(5)[0x7e(126), Sequence(int8), ClientSentAtElapsedFromOrigin(long; Ms), Nil, ] + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(buffer.Slice(bytesWritten), 5, out written), written, ref bytesWritten); + // 0:Type = 0x7e / 126 (Heartbeat) + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), 0x7e, out written), written, ref bytesWritten); + // 1:Sequence + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), sequence, out written), written, ref bytesWritten); + // 2:ClientSentAtElapsedFromOrigin + VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), clientSentAt, out written), written, ref bytesWritten); + // 3:Reserved (Nil) + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(buffer.Slice(bytesWritten), out written), written, ref bytesWritten); + // 4:Reserved (Nil) + VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(buffer.Slice(bytesWritten), out written), written, ref bytesWritten); + + bufferWriter.Advance(bytesWritten); + } - /// - /// Writes a client heartbeat message for sending response from the server. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteClientHeartbeatMessageResponse(IBufferWriter bufferWriter, short sequence, long clientSentAt) + static void VerifyResultAndAdvance(bool result, int written, ref int bytesWrittenTotal) + { + if (!result) { - var written = 0; - var bytesWritten = 0; - var buffer = bufferWriter.GetSpan(32); - - // Array(5)[0x7e(126), Sequence(int8), ClientSentAtElapsedFromOrigin(long; Ms), Nil, ] - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteArrayHeader(buffer.Slice(bytesWritten), 5, out written), written, ref bytesWritten); - // 0:Type = 0x7e / 126 (Heartbeat) - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), 0x7e, out written), written, ref bytesWritten); - // 1:Sequence - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), sequence, out written), written, ref bytesWritten); - // 2:ClientSentAtElapsedFromOrigin - VerifyResultAndAdvance(MessagePackPrimitives.TryWrite(buffer.Slice(bytesWritten), clientSentAt, out written), written, ref bytesWritten); - // 3:Reserved (Nil) - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(buffer.Slice(bytesWritten), out written), written, ref bytesWritten); - // 4:Reserved (Nil) - VerifyResultAndAdvance(MessagePackPrimitives.TryWriteNil(buffer.Slice(bytesWritten), out written), written, ref bytesWritten); - - bufferWriter.Advance(bytesWritten); + throw new InvalidOperationException($"Insufficient buffer size."); } - static void VerifyResultAndAdvance(bool result, int written, ref int bytesWrittenTotal) - { - if (!result) - { - throw new InvalidOperationException($"Insufficient buffer size."); - } - - bytesWrittenTotal += written; - } + bytesWrittenTotal += written; } +} - internal enum StreamingHubMessageType - { - /// - /// Request: Client -> Server - /// - Request, - /// - /// Request: Client -> Server / Fire-and-Forget - /// - RequestFireAndForget, - /// - /// Request: Client -> Server -> Client - /// - Response, - /// - /// Request: Client -> Server -(Error)-> Client - /// - ResponseWithError, - - /// - /// Broadcast: Server -> Client - /// - Broadcast, - - /// - /// ClientResult: Server -> Client - /// - ClientResultRequest, - /// - /// ClientResult: Server -> Client -> Server - /// - ClientResultResponse, - /// - /// ClientResult: Server -> Client -(Error)-> Server - /// - ClientResultResponseWithError, - - - /// - /// Heartbeat: Server -> Client -> Server - /// - ServerHeartbeatResponse, - /// - /// Heartbeat: Server -> Client - /// - ServerHeartbeat, - - /// - /// Heartbeat: Client -> Server - /// - ClientHeartbeat, - /// - /// Heartbeat: Client -> Server -> Client - /// - ClientHeartbeatResponse, - } +internal enum StreamingHubMessageType +{ + /// + /// Request: Client -> Server + /// + Request, + /// + /// Request: Client -> Server / Fire-and-Forget + /// + RequestFireAndForget, + /// + /// Request: Client -> Server -> Client + /// + Response, + /// + /// Request: Client -> Server -(Error)-> Client + /// + ResponseWithError, + + /// + /// Broadcast: Server -> Client + /// + Broadcast, + + /// + /// ClientResult: Server -> Client + /// + ClientResultRequest, + /// + /// ClientResult: Server -> Client -> Server + /// + ClientResultResponse, + /// + /// ClientResult: Server -> Client -(Error)-> Server + /// + ClientResultResponseWithError, + + + /// + /// Heartbeat: Server -> Client -> Server + /// + ServerHeartbeatResponse, + /// + /// Heartbeat: Server -> Client + /// + ServerHeartbeat, + + /// + /// Heartbeat: Client -> Server + /// + ClientHeartbeat, + /// + /// Heartbeat: Client -> Server -> Client + /// + ClientHeartbeatResponse, } diff --git a/src/MagicOnion.Internal/StreamingHubPayload.cs b/src/MagicOnion.Internal/StreamingHubPayload.cs index e61398cca..8af98da74 100644 --- a/src/MagicOnion.Internal/StreamingHubPayload.cs +++ b/src/MagicOnion.Internal/StreamingHubPayload.cs @@ -1,161 +1,160 @@ using System.Buffers; using System.Diagnostics.CodeAnalysis; -namespace MagicOnion.Internal -{ +namespace MagicOnion.Internal; + #if DEBUG - internal class StreamingHubPayload - { - readonly short version; +internal class StreamingHubPayload +{ + readonly short version; #if STREAMINGHUBPAYLOAD_TRACK_LOCATION string? payloadCreatedLocation; string? payloadReturnLocation; #endif - internal StreamingHubPayloadCore Core { get; } + internal StreamingHubPayloadCore Core { get; } - public int Length + public int Length + { + get { - get - { - ThrowIfVersionHasChanged(); - return Core.Length; - } + ThrowIfVersionHasChanged(); + return Core.Length; } + } - public ReadOnlyMemory Memory + public ReadOnlyMemory Memory + { + get { - get - { - ThrowIfVersionHasChanged(); - return Core.Memory; - } + ThrowIfVersionHasChanged(); + return Core.Memory; } + } - public ReadOnlySpan Span + public ReadOnlySpan Span + { + get { - get - { - ThrowIfVersionHasChanged(); - return Core.Span; - } + ThrowIfVersionHasChanged(); + return Core.Span; } + } - public StreamingHubPayload(StreamingHubPayloadCore core) - { - this.Core = core; - this.version = core.Version; + public StreamingHubPayload(StreamingHubPayloadCore core) + { + this.Core = core; + this.version = core.Version; #if STREAMINGHUBPAYLOAD_TRACK_LOCATION this.payloadCreatedLocation = Environment.StackTrace; #endif - } + } - void ThrowIfVersionHasChanged() - { - if (Core.Version != version) throw new InvalidOperationException("StreamingHubPayload version is mismatched."); - } + void ThrowIfVersionHasChanged() + { + if (Core.Version != version) throw new InvalidOperationException("StreamingHubPayload version is mismatched."); + } - public void MarkAsReturned() - { + public void MarkAsReturned() + { #if STREAMINGHUBPAYLOAD_TRACK_LOCATION payloadReturnLocation = Environment.StackTrace; #endif - } } +} #else internal class StreamingHubPayload : StreamingHubPayloadCore {} #endif - internal class StreamingHubPayloadCore - { - byte[]? buffer; - ReadOnlyMemory? memory; +internal class StreamingHubPayloadCore +{ + byte[]? buffer; + ReadOnlyMemory? memory; #if DEBUG - public short Version { get; private set; } + public short Version { get; private set; } #endif - public int Length => memory!.Value.Length; - public ReadOnlySpan Span => memory!.Value.Span; - public ReadOnlyMemory Memory => memory!.Value; + public int Length => memory!.Value.Length; + public ReadOnlySpan Span => memory!.Value.Span; + public ReadOnlyMemory Memory => memory!.Value; - public void Initialize(ReadOnlySpan data) - { - ThrowIfUsing(); + public void Initialize(ReadOnlySpan data) + { + ThrowIfUsing(); - buffer = ArrayPool.Shared.Rent(data.Length); - data.CopyTo(buffer); - memory = buffer.AsMemory(0, (int)data.Length); - } + buffer = ArrayPool.Shared.Rent(data.Length); + data.CopyTo(buffer); + memory = buffer.AsMemory(0, (int)data.Length); + } - public void Initialize(ReadOnlySequence data) - { - ThrowIfUsing(); - if (data.Length > int.MaxValue) throw new InvalidOperationException("A body size of StreamingHubPayload must be less than int.MaxValue"); + public void Initialize(ReadOnlySequence data) + { + ThrowIfUsing(); + if (data.Length > int.MaxValue) throw new InvalidOperationException("A body size of StreamingHubPayload must be less than int.MaxValue"); + buffer = ArrayPool.Shared.Rent((int)data.Length); + data.CopyTo(buffer); + memory = buffer.AsMemory(0, (int)data.Length); + } + + public void Initialize(ReadOnlyMemory data, bool holdReference) + { + ThrowIfUsing(); + + if (holdReference) + { + buffer = null; + memory = data; + } + else + { buffer = ArrayPool.Shared.Rent((int)data.Length); data.CopyTo(buffer); memory = buffer.AsMemory(0, (int)data.Length); } + } - public void Initialize(ReadOnlyMemory data, bool holdReference) - { - ThrowIfUsing(); - - if (holdReference) - { - buffer = null; - memory = data; - } - else - { - buffer = ArrayPool.Shared.Rent((int)data.Length); - data.CopyTo(buffer); - memory = buffer.AsMemory(0, (int)data.Length); - } - } + public void Uninitialize() + { + ThrowIfUninitialized(); - public void Uninitialize() + if (buffer != null) { - ThrowIfUninitialized(); - - if (buffer != null) - { #if DEBUG && NET6_0_OR_GREATER - Array.Fill(buffer, 0xff); + Array.Fill(buffer, 0xff); #endif - ArrayPool.Shared.Return(buffer); - } + ArrayPool.Shared.Return(buffer); + } - memory = null; - buffer = null; + memory = null; + buffer = null; #if DEBUG - Version++; + Version++; #endif - } + } #if !UNITY_2021_1_OR_NEWER && !NETSTANDARD2_0 && !NETSTANDARD2_1 - [MemberNotNull(nameof(memory))] + [MemberNotNull(nameof(memory))] #endif - void ThrowIfUninitialized() + void ThrowIfUninitialized() + { + //Debug.Assert(memory is not null); + if (memory is null) { - //Debug.Assert(memory is not null); - if (memory is null) - { - throw new InvalidOperationException("A StreamingHubPayload has been already uninitialized."); - } + throw new InvalidOperationException("A StreamingHubPayload has been already uninitialized."); } + } - void ThrowIfUsing() + void ThrowIfUsing() + { + //Debug.Assert(memory is null); + if (memory is not null) { - //Debug.Assert(memory is null); - if (memory is not null) - { - throw new InvalidOperationException("A StreamingHubPayload is currently used by other caller."); - } + throw new InvalidOperationException("A StreamingHubPayload is currently used by other caller."); } } } diff --git a/src/MagicOnion.Internal/StreamingHubPayloadPool.BuiltIn.cs b/src/MagicOnion.Internal/StreamingHubPayloadPool.BuiltIn.cs index 8030a54da..1f41033f2 100644 --- a/src/MagicOnion.Internal/StreamingHubPayloadPool.BuiltIn.cs +++ b/src/MagicOnion.Internal/StreamingHubPayloadPool.BuiltIn.cs @@ -3,115 +3,114 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +internal class ObjectPool where T : class { - internal class ObjectPool where T : class - { - readonly Func factory; + readonly Func factory; - T? item1; - T? item2; - T? item3; - T? item4; + T? item1; + T? item2; + T? item3; + T? item4; - public ObjectPool(Func factory) - { - this.factory = factory; - } + public ObjectPool(Func factory) + { + this.factory = factory; + } - public T RentOrCreateCore() + public T RentOrCreateCore() + { + T? tmpItem; + if (!(TryGet(ref item1, out tmpItem) || + TryGet(ref item2, out tmpItem) || + TryGet(ref item3, out tmpItem) || + TryGet(ref item4, out tmpItem))) { - T? tmpItem; - if (!(TryGet(ref item1, out tmpItem) || - TryGet(ref item2, out tmpItem) || - TryGet(ref item3, out tmpItem) || - TryGet(ref item4, out tmpItem))) - { - tmpItem = factory(); - } - - return tmpItem; + tmpItem = factory(); } - public void ReturnCore(T item) - { - var pooled = TryReturn(ref item1, item) || - TryReturn(ref item2, item) || - TryReturn(ref item3, item) || - TryReturn(ref item4, item); - } + return tmpItem; + } + + public void ReturnCore(T item) + { + var pooled = TryReturn(ref item1, item) || + TryReturn(ref item2, item) || + TryReturn(ref item3, item) || + TryReturn(ref item4, item); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - bool TryReturn(ref T? field, T payload) - => Interlocked.CompareExchange(ref field, payload, null) == null; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + bool TryReturn(ref T? field, T payload) + => Interlocked.CompareExchange(ref field, payload, null) == null; - bool TryGet(ref T? field, [NotNullWhen(true)] out T? item) + bool TryGet(ref T? field, [NotNullWhen(true)] out T? item) + { + var tmp = field; + if (tmp != null && Interlocked.CompareExchange(ref field, null, tmp) == tmp) { - var tmp = field; - if (tmp != null && Interlocked.CompareExchange(ref field, null, tmp) == tmp) - { - item = tmp; - return true; - } - - item = null; - return false; + item = tmp; + return true; } + + item = null; + return false; } +} - internal class StreamingHubPayloadPool - { +internal class StreamingHubPayloadPool +{ #if DEBUG - readonly ObjectPool pool = new(static () => new StreamingHubPayloadCore()); + readonly ObjectPool pool = new(static () => new StreamingHubPayloadCore()); #else - readonly ObjectPool pool = new(static () => new StreamingHubPayload()); + readonly ObjectPool pool = new(static () => new StreamingHubPayload()); #endif - public static StreamingHubPayloadPool Shared { get; } = new(); + public static StreamingHubPayloadPool Shared { get; } = new(); - public void Return(StreamingHubPayload payload) - { + public void Return(StreamingHubPayload payload) + { #if DEBUG - payload.Core.Uninitialize(); - pool.ReturnCore(payload.Core); + payload.Core.Uninitialize(); + pool.ReturnCore(payload.Core); #else - payload.Uninitialize(); - pool.ReturnCore(payload); + payload.Uninitialize(); + pool.ReturnCore(payload); #endif - } + } - public StreamingHubPayload RentOrCreate(ReadOnlySequence data) - { - var payload = pool.RentOrCreateCore(); - payload.Initialize(data); + public StreamingHubPayload RentOrCreate(ReadOnlySequence data) + { + var payload = pool.RentOrCreateCore(); + payload.Initialize(data); #if DEBUG - return new StreamingHubPayload(payload); + return new StreamingHubPayload(payload); #else - return (StreamingHubPayload)payload; + return (StreamingHubPayload)payload; #endif - } + } - public StreamingHubPayload RentOrCreate(ReadOnlySpan data) - { - var payload = pool.RentOrCreateCore(); - payload.Initialize(data); + public StreamingHubPayload RentOrCreate(ReadOnlySpan data) + { + var payload = pool.RentOrCreateCore(); + payload.Initialize(data); #if DEBUG - return new StreamingHubPayload(payload); + return new StreamingHubPayload(payload); #else - return (StreamingHubPayload)payload; + return (StreamingHubPayload)payload; #endif - } + } - public StreamingHubPayload RentOrCreate(ReadOnlyMemory data, bool holdReference) - { - var payload = pool.RentOrCreateCore(); - payload.Initialize(data, holdReference); + public StreamingHubPayload RentOrCreate(ReadOnlyMemory data, bool holdReference) + { + var payload = pool.RentOrCreateCore(); + payload.Initialize(data, holdReference); #if DEBUG - return new StreamingHubPayload(payload); + return new StreamingHubPayload(payload); #else - return (StreamingHubPayload)payload; + return (StreamingHubPayload)payload; #endif - } } } #endif diff --git a/src/MagicOnion.Internal/StreamingHubServerMessageReader.cs b/src/MagicOnion.Internal/StreamingHubServerMessageReader.cs index dcedfcb63..6a8fe7c50 100644 --- a/src/MagicOnion.Internal/StreamingHubServerMessageReader.cs +++ b/src/MagicOnion.Internal/StreamingHubServerMessageReader.cs @@ -1,114 +1,113 @@ using MessagePack; -namespace MagicOnion.Internal +namespace MagicOnion.Internal; + +internal ref struct StreamingHubServerMessageReader { - internal ref struct StreamingHubServerMessageReader + readonly ReadOnlyMemory data; + int position; + + public StreamingHubServerMessageReader(ReadOnlyMemory data) { - readonly ReadOnlyMemory data; - int position; + this.data = data; + this.position = 0; + } - public StreamingHubServerMessageReader(ReadOnlyMemory data) + void VerifyResultAndAdvance(MessagePackPrimitives.DecodeResult result, int readLen) + { + if (result != MessagePackPrimitives.DecodeResult.Success) { - this.data = data; - this.position = 0; + throw new InvalidOperationException($"Invalid message format: {result}"); } + position += readLen; + } - void VerifyResultAndAdvance(MessagePackPrimitives.DecodeResult result, int readLen) - { - if (result != MessagePackPrimitives.DecodeResult.Success) - { - throw new InvalidOperationException($"Invalid message format: {result}"); - } - position += readLen; - } + public StreamingHubMessageType ReadMessageType() + { + VerifyResultAndAdvance(MessagePackPrimitives.TryReadArrayHeader(data.Span.Slice(position), out var arrayLength, out var read), read); - public StreamingHubMessageType ReadMessageType() - { - VerifyResultAndAdvance(MessagePackPrimitives.TryReadArrayHeader(data.Span.Slice(position), out var arrayLength, out var read), read); - - return arrayLength switch - { - 2 => StreamingHubMessageType.RequestFireAndForget, - 3 => StreamingHubMessageType.Request, - 4 => ReadMessageSubType(), - _ => throw new InvalidOperationException($"Unknown message format: ArrayLength = {arrayLength}"), - }; - } - StreamingHubMessageType ReadMessageSubType() + return arrayLength switch { - VerifyResultAndAdvance(MessagePackPrimitives.TryReadByte(data.Span.Slice(position), out var subType, out var read), read); - - return subType switch - { - 0x00 => StreamingHubMessageType.ClientResultResponse, - 0x01 => StreamingHubMessageType.ClientResultResponseWithError, - 0x7e => StreamingHubMessageType.ClientHeartbeat, - 0x7f => StreamingHubMessageType.ServerHeartbeatResponse, - _ => throw new InvalidOperationException($"Unknown client response message: {subType}"), - }; - } + 2 => StreamingHubMessageType.RequestFireAndForget, + 3 => StreamingHubMessageType.Request, + 4 => ReadMessageSubType(), + _ => throw new InvalidOperationException($"Unknown message format: ArrayLength = {arrayLength}"), + }; + } + StreamingHubMessageType ReadMessageSubType() + { + VerifyResultAndAdvance(MessagePackPrimitives.TryReadByte(data.Span.Slice(position), out var subType, out var read), read); - public (int MethodId, ReadOnlyMemory Body) ReadRequestFireAndForget() + return subType switch { - // void: [methodId, [argument]] - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var methodId, out var read), read); + 0x00 => StreamingHubMessageType.ClientResultResponse, + 0x01 => StreamingHubMessageType.ClientResultResponseWithError, + 0x7e => StreamingHubMessageType.ClientHeartbeat, + 0x7f => StreamingHubMessageType.ServerHeartbeatResponse, + _ => throw new InvalidOperationException($"Unknown client response message: {subType}"), + }; + } - return (methodId, data.Slice(position)); - } + public (int MethodId, ReadOnlyMemory Body) ReadRequestFireAndForget() + { + // void: [methodId, [argument]] + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var methodId, out var read), read); - public (int MessageId, int MethodId, ReadOnlyMemory Body) ReadRequest() - { - // T: [messageId, methodId, [argument]] - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var messageId, out var readLenMessageId), readLenMessageId); - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var methodId, out var readLenMethodId), readLenMethodId); + return (methodId, data.Slice(position)); + } - return (messageId, methodId, data.Slice(position)); - } + public (int MessageId, int MethodId, ReadOnlyMemory Body) ReadRequest() + { + // T: [messageId, methodId, [argument]] + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var messageId, out var readLenMessageId), readLenMessageId); + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt32(data.Span.Slice(position), out var methodId, out var readLenMethodId), readLenMethodId); - public (Guid ClientResultMessageId, int ClientMethodId, ReadOnlyMemory Body) ReadClientResultResponse() - { - // T: [0, clientResultMessageId, methodId, result] - var reader = new MessagePackReader(data.Slice(position)); - var clientResultMessageId = MessagePackSerializer.Deserialize(ref reader); - var clientMethodId = reader.ReadInt32(); - position += (int)reader.Consumed; + return (messageId, methodId, data.Slice(position)); + } - return (clientResultMessageId, clientMethodId, data.Slice(position)); - } + public (Guid ClientResultMessageId, int ClientMethodId, ReadOnlyMemory Body) ReadClientResultResponse() + { + // T: [0, clientResultMessageId, methodId, result] + var reader = new MessagePackReader(data.Slice(position)); + var clientResultMessageId = MessagePackSerializer.Deserialize(ref reader); + var clientMethodId = reader.ReadInt32(); + position += (int)reader.Consumed; - public (Guid ClientResultMessageId, int ClientMethodId, int StatusCode, string Detail, string Message) ReadClientResultResponseForError() - { - // T: [1, clientResultMessageId, methodId, [statusCode, detail, message]] - var reader = new MessagePackReader(data.Slice(position)); - var clientResultMessageId = MessagePackSerializer.Deserialize(ref reader); - var clientMethodId = reader.ReadInt32(); - var bodyArray = reader.ReadArrayHeader(); - if (bodyArray != 3) throw new InvalidOperationException($"Invalid ClientResponse: The BodyArray length is {bodyArray}"); + return (clientResultMessageId, clientMethodId, data.Slice(position)); + } - var statusCode = reader.ReadInt32(); - var detail = reader.ReadString() ?? string.Empty; - var message = reader.ReadString() ?? string.Empty; + public (Guid ClientResultMessageId, int ClientMethodId, int StatusCode, string Detail, string Message) ReadClientResultResponseForError() + { + // T: [1, clientResultMessageId, methodId, [statusCode, detail, message]] + var reader = new MessagePackReader(data.Slice(position)); + var clientResultMessageId = MessagePackSerializer.Deserialize(ref reader); + var clientMethodId = reader.ReadInt32(); + var bodyArray = reader.ReadArrayHeader(); + if (bodyArray != 3) throw new InvalidOperationException($"Invalid ClientResponse: The BodyArray length is {bodyArray}"); - position += (int)reader.Consumed; + var statusCode = reader.ReadInt32(); + var detail = reader.ReadString() ?? string.Empty; + var message = reader.ReadString() ?? string.Empty; - return (clientResultMessageId, clientMethodId, statusCode, detail, message); - } + position += (int)reader.Consumed; - public (short Sequence, long ClientSentAt, ReadOnlyMemory Extra) ReadClientHeartbeat() - { - // [Sequence(int16), ClientSentAt(long), ] - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt16(data.Span.Slice(position), out var sequence, out var readLenSequence), readLenSequence); // Sequence - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt64(data.Span.Slice(position), out var clientSentAt, out var readLenClientSentAt), readLenClientSentAt); // ClientSentAt + return (clientResultMessageId, clientMethodId, statusCode, detail, message); + } - return (sequence, clientSentAt, data.Slice(position)); - } + public (short Sequence, long ClientSentAt, ReadOnlyMemory Extra) ReadClientHeartbeat() + { + // [Sequence(int16), ClientSentAt(long), ] + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt16(data.Span.Slice(position), out var sequence, out var readLenSequence), readLenSequence); // Sequence + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt64(data.Span.Slice(position), out var clientSentAt, out var readLenClientSentAt), readLenClientSentAt); // ClientSentAt - public short ReadServerHeartbeatResponse() - { - // [Sequence(int16), Nil, Nil] - VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt16(data.Span.Slice(position), out var sequence, out var readLenSequence), readLenSequence); // Sequence + return (sequence, clientSentAt, data.Slice(position)); + } - return sequence; - } + public short ReadServerHeartbeatResponse() + { + // [Sequence(int16), Nil, Nil] + VerifyResultAndAdvance(MessagePackPrimitives.TryReadInt16(data.Span.Slice(position), out var sequence, out var readLenSequence), readLenSequence); // Sequence + + return sequence; } } diff --git a/src/MagicOnion.Serialization.MemoryPack/DynamicArgumentTupleMemoryPackFormatter.cs b/src/MagicOnion.Serialization.MemoryPack/DynamicArgumentTupleMemoryPackFormatter.cs index da1a16f8b..dd6915c87 100644 --- a/src/MagicOnion.Serialization.MemoryPack/DynamicArgumentTupleMemoryPackFormatter.cs +++ b/src/MagicOnion.Serialization.MemoryPack/DynamicArgumentTupleMemoryPackFormatter.cs @@ -5,760 +5,759 @@ using System.Runtime.CompilerServices; using MemoryPack; -namespace MagicOnion.Serialization.MemoryPack +namespace MagicOnion.Serialization.MemoryPack; + +public static class DynamicArgumentTupleFormatter { - public static class DynamicArgumentTupleFormatter + static bool isRegistered = false; + public static void Register() { - static bool isRegistered = false; - public static void Register() - { - if (isRegistered) return; - isRegistered = true; - - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,>), typeof(DynamicArgumentTupleFormatter<,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,>), typeof(DynamicArgumentTupleFormatter<,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,>), typeof(DynamicArgumentTupleFormatter<,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,,,,,>)); - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,,,,,,>)); - } + if (isRegistered) return; + isRegistered = true; + + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,>), typeof(DynamicArgumentTupleFormatter<,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,>), typeof(DynamicArgumentTupleFormatter<,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,>), typeof(DynamicArgumentTupleFormatter<,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,,,,,>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<,,,,,,,,,,,,,,>), typeof(DynamicArgumentTupleFormatter<,,,,,,,,,,,,,,>)); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); - writer.WriteValue(value.Item6); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + writer.WriteValue(value.Item6); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); - writer.WriteValue(value.Item6); - writer.WriteValue(value.Item7); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + writer.WriteValue(value.Item6); + writer.WriteValue(value.Item7); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); - writer.WriteValue(value.Item6); - writer.WriteValue(value.Item7); - writer.WriteValue(value.Item8); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + writer.WriteValue(value.Item6); + writer.WriteValue(value.Item7); + writer.WriteValue(value.Item8); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); - writer.WriteValue(value.Item6); - writer.WriteValue(value.Item7); - writer.WriteValue(value.Item8); - writer.WriteValue(value.Item9); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + writer.WriteValue(value.Item6); + writer.WriteValue(value.Item7); + writer.WriteValue(value.Item8); + writer.WriteValue(value.Item9); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); - writer.WriteValue(value.Item6); - writer.WriteValue(value.Item7); - writer.WriteValue(value.Item8); - writer.WriteValue(value.Item9); - writer.WriteValue(value.Item10); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + writer.WriteValue(value.Item6); + writer.WriteValue(value.Item7); + writer.WriteValue(value.Item8); + writer.WriteValue(value.Item9); + writer.WriteValue(value.Item10); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); - writer.WriteValue(value.Item6); - writer.WriteValue(value.Item7); - writer.WriteValue(value.Item8); - writer.WriteValue(value.Item9); - writer.WriteValue(value.Item10); - writer.WriteValue(value.Item11); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + writer.WriteValue(value.Item6); + writer.WriteValue(value.Item7); + writer.WriteValue(value.Item8); + writer.WriteValue(value.Item9); + writer.WriteValue(value.Item10); + writer.WriteValue(value.Item11); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); - writer.WriteValue(value.Item6); - writer.WriteValue(value.Item7); - writer.WriteValue(value.Item8); - writer.WriteValue(value.Item9); - writer.WriteValue(value.Item10); - writer.WriteValue(value.Item11); - writer.WriteValue(value.Item12); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + writer.WriteValue(value.Item6); + writer.WriteValue(value.Item7); + writer.WriteValue(value.Item8); + writer.WriteValue(value.Item9); + writer.WriteValue(value.Item10); + writer.WriteValue(value.Item11); + writer.WriteValue(value.Item12); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); - writer.WriteValue(value.Item6); - writer.WriteValue(value.Item7); - writer.WriteValue(value.Item8); - writer.WriteValue(value.Item9); - writer.WriteValue(value.Item10); - writer.WriteValue(value.Item11); - writer.WriteValue(value.Item12); - writer.WriteValue(value.Item13); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + writer.WriteValue(value.Item6); + writer.WriteValue(value.Item7); + writer.WriteValue(value.Item8); + writer.WriteValue(value.Item9); + writer.WriteValue(value.Item10); + writer.WriteValue(value.Item11); + writer.WriteValue(value.Item12); + writer.WriteValue(value.Item13); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); - writer.WriteValue(value.Item6); - writer.WriteValue(value.Item7); - writer.WriteValue(value.Item8); - writer.WriteValue(value.Item9); - writer.WriteValue(value.Item10); - writer.WriteValue(value.Item11); - writer.WriteValue(value.Item12); - writer.WriteValue(value.Item13); - writer.WriteValue(value.Item14); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + writer.WriteValue(value.Item6); + writer.WriteValue(value.Item7); + writer.WriteValue(value.Item8); + writer.WriteValue(value.Item9); + writer.WriteValue(value.Item10); + writer.WriteValue(value.Item11); + writer.WriteValue(value.Item12); + writer.WriteValue(value.Item13); + writer.WriteValue(value.Item14); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } + + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); } +} +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter : MemoryPackFormatter> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter : MemoryPackFormatter> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } - writer.WriteValue(value.Item1); - writer.WriteValue(value.Item2); - writer.WriteValue(value.Item3); - writer.WriteValue(value.Item4); - writer.WriteValue(value.Item5); - writer.WriteValue(value.Item6); - writer.WriteValue(value.Item7); - writer.WriteValue(value.Item8); - writer.WriteValue(value.Item9); - writer.WriteValue(value.Item10); - writer.WriteValue(value.Item11); - writer.WriteValue(value.Item12); - writer.WriteValue(value.Item13); - writer.WriteValue(value.Item14); - writer.WriteValue(value.Item15); + writer.DangerousWriteUnmanaged(value); + return; } + writer.WriteValue(value.Item1); + writer.WriteValue(value.Item2); + writer.WriteValue(value.Item3); + writer.WriteValue(value.Item4); + writer.WriteValue(value.Item5); + writer.WriteValue(value.Item6); + writer.WriteValue(value.Item7); + writer.WriteValue(value.Item8); + writer.WriteValue(value.Item9); + writer.WriteValue(value.Item10); + writer.WriteValue(value.Item11); + writer.WriteValue(value.Item12); + writer.WriteValue(value.Item13); + writer.WriteValue(value.Item14); + writer.WriteValue(value.Item15); + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } - - value = new DynamicArgumentTuple( - reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - , reader.ReadValue() - ); + reader.DangerousReadUnmanaged(out value); + return; } - } + value = new DynamicArgumentTuple( + reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + , reader.ReadValue() + ); + } } + diff --git a/src/MagicOnion.Serialization.MemoryPack/DynamicArgumentTupleMemoryPackFormatter.tt b/src/MagicOnion.Serialization.MemoryPack/DynamicArgumentTupleMemoryPackFormatter.tt index 8e922731c..aa7fe28e0 100644 --- a/src/MagicOnion.Serialization.MemoryPack/DynamicArgumentTupleMemoryPackFormatter.tt +++ b/src/MagicOnion.Serialization.MemoryPack/DynamicArgumentTupleMemoryPackFormatter.tt @@ -11,67 +11,66 @@ using System.Runtime.CompilerServices; using MemoryPack; -namespace MagicOnion.Serialization.MemoryPack +namespace MagicOnion.Serialization.MemoryPack; + +public static class DynamicArgumentTupleFormatter { - public static class DynamicArgumentTupleFormatter + static bool isRegistered = false; + public static void Register() { - static bool isRegistered = false; - public static void Register() - { - if (isRegistered) return; - isRegistered = true; + if (isRegistered) return; + isRegistered = true; <# for (var i = 2; i < 16; i++) { #> - MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<<#= new String(',', i - 1) #>>), typeof(DynamicArgumentTupleFormatter<<#= new String(',', i - 1) #>>)); + MemoryPackFormatterProvider.RegisterGenericType(typeof(DynamicArgumentTuple<<#= new String(',', i - 1) #>>), typeof(DynamicArgumentTupleFormatter<<#= new String(',', i - 1) #>>)); <# } #> - } } +} <# for (var i = 2; i < 16; i++) { var dynamicArgumentTupleFormatterGenericArgs = string.Join(", ", Enumerable.Range(1, i).Select(x => $"T{x}")); var dynamicArgumentTupleGenericArgs = string.Join(", ", Enumerable.Range(1, i).Select(x => $"T{x}?")); #> +[global::MagicOnion.Serialization.MemoryPack.Preserve] +public class DynamicArgumentTupleFormatter<<#= dynamicArgumentTupleFormatterGenericArgs #>> : MemoryPackFormatter>> +{ [global::MagicOnion.Serialization.MemoryPack.Preserve] - public class DynamicArgumentTupleFormatter<<#= dynamicArgumentTupleFormatterGenericArgs #>> : MemoryPackFormatter>> - { - [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple<<#= dynamicArgumentTupleGenericArgs #>> value) + public override void Serialize(ref MemoryPackWriter writer, ref DynamicArgumentTuple<<#= dynamicArgumentTupleGenericArgs #>> value) #else - public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple<<#= dynamicArgumentTupleGenericArgs #>> value) + public override void Serialize(ref MemoryPackWriter writer, scoped ref DynamicArgumentTuple<<#= dynamicArgumentTupleGenericArgs #>> value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>>()) - { - writer.DangerousWriteUnmanaged(value); - return; - } + writer.DangerousWriteUnmanaged(value); + return; + } <# for (var j = 1; j <= i; j++) { #> - writer.WriteValue(value.Item<#= j #>); + writer.WriteValue(value.Item<#= j #>); <# } #> - } + } - [global::MagicOnion.Serialization.MemoryPack.Preserve] + [global::MagicOnion.Serialization.MemoryPack.Preserve] #if UNITY_2021_3_OR_NEWER - public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple<<#= dynamicArgumentTupleGenericArgs #>> value) + public override void Deserialize(ref MemoryPackReader reader, ref DynamicArgumentTuple<<#= dynamicArgumentTupleGenericArgs #>> value) #else - public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple<<#= dynamicArgumentTupleGenericArgs #>> value) + public override void Deserialize(ref MemoryPackReader reader, scoped ref DynamicArgumentTuple<<#= dynamicArgumentTupleGenericArgs #>> value) #endif + { + if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>>()) { - if (!System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences>>()) - { - reader.DangerousReadUnmanaged(out value); - return; - } + reader.DangerousReadUnmanaged(out value); + return; + } - value = new DynamicArgumentTuple<<#= dynamicArgumentTupleGenericArgs #>>( + value = new DynamicArgumentTuple<<#= dynamicArgumentTupleGenericArgs #>>( <# for (var j = 1; j <= i; j++) { #> - <# if (j != 1) { #>, <# } #>reader.ReadValue?>() + <# if (j != 1) { #>, <# } #>reader.ReadValue?>() <# } #> - ); - } + ); } +} <# } #> -} diff --git a/src/MagicOnion.Serialization.MemoryPack/MemoryPackMagicOnionSerializer.cs b/src/MagicOnion.Serialization.MemoryPack/MemoryPackMagicOnionSerializer.cs index d14084703..a704ae00f 100644 --- a/src/MagicOnion.Serialization.MemoryPack/MemoryPackMagicOnionSerializer.cs +++ b/src/MagicOnion.Serialization.MemoryPack/MemoryPackMagicOnionSerializer.cs @@ -1,48 +1,46 @@ -#nullable enable using System.Buffers; using System.Reflection; using Grpc.Core; using MemoryPack; -namespace MagicOnion.Serialization.MemoryPack +namespace MagicOnion.Serialization.MemoryPack; + +public partial class MemoryPackMagicOnionSerializerProvider : IMagicOnionSerializerProvider { - public partial class MemoryPackMagicOnionSerializerProvider : IMagicOnionSerializerProvider + readonly MemoryPackSerializerOptions serializerOptions; + public static MemoryPackMagicOnionSerializerProvider Instance { get; } = new MemoryPackMagicOnionSerializerProvider(MemoryPackSerializerOptions.Default); + + MemoryPackMagicOnionSerializerProvider(MemoryPackSerializerOptions serializerOptions) { - readonly MemoryPackSerializerOptions serializerOptions; - public static MemoryPackMagicOnionSerializerProvider Instance { get; } = new MemoryPackMagicOnionSerializerProvider(MemoryPackSerializerOptions.Default); + this.serializerOptions = serializerOptions; + } - MemoryPackMagicOnionSerializerProvider(MemoryPackSerializerOptions serializerOptions) - { - this.serializerOptions = serializerOptions; - } + static MemoryPackMagicOnionSerializerProvider() + { + DynamicArgumentTupleFormatter.Register(); + } - static MemoryPackMagicOnionSerializerProvider() - { - DynamicArgumentTupleFormatter.Register(); - } + public MemoryPackMagicOnionSerializerProvider WithOptions(MemoryPackSerializerOptions serializerOptions) + => new MemoryPackMagicOnionSerializerProvider(serializerOptions); - public MemoryPackMagicOnionSerializerProvider WithOptions(MemoryPackSerializerOptions serializerOptions) - => new MemoryPackMagicOnionSerializerProvider(serializerOptions); + public IMagicOnionSerializer Create(MethodType methodType, MethodInfo? methodInfo) + { + return new MagicOnionSerializer(serializerOptions); + } - public IMagicOnionSerializer Create(MethodType methodType, MethodInfo? methodInfo) - { - return new MagicOnionSerializer(serializerOptions); - } + class MagicOnionSerializer : IMagicOnionSerializer + { + readonly MemoryPackSerializerOptions serializerOptions; - class MagicOnionSerializer : IMagicOnionSerializer + public MagicOnionSerializer(MemoryPackSerializerOptions serializerOptions) { - readonly MemoryPackSerializerOptions serializerOptions; - - public MagicOnionSerializer(MemoryPackSerializerOptions serializerOptions) - { - this.serializerOptions = serializerOptions; - } + this.serializerOptions = serializerOptions; + } - public void Serialize(IBufferWriter writer, in T value) - => MemoryPackSerializer.Serialize(writer, value, serializerOptions); + public void Serialize(IBufferWriter writer, in T value) + => MemoryPackSerializer.Serialize(writer, value, serializerOptions); - public T Deserialize(in ReadOnlySequence bytes) - => MemoryPackSerializer.Deserialize(bytes, serializerOptions)!; - } + public T Deserialize(in ReadOnlySequence bytes) + => MemoryPackSerializer.Deserialize(bytes, serializerOptions)!; } } diff --git a/src/MagicOnion.Serialization.MemoryPack/PreserveAttribute.cs b/src/MagicOnion.Serialization.MemoryPack/PreserveAttribute.cs index 3b0e0887e..140c64127 100644 --- a/src/MagicOnion.Serialization.MemoryPack/PreserveAttribute.cs +++ b/src/MagicOnion.Serialization.MemoryPack/PreserveAttribute.cs @@ -1,11 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Text; +namespace MagicOnion.Serialization.MemoryPack; -namespace MagicOnion.Serialization.MemoryPack +[AttributeUsage(AttributeTargets.All)] +internal class PreserveAttribute : Attribute { - [AttributeUsage(AttributeTargets.All)] - internal class PreserveAttribute : Attribute - { - } } diff --git a/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.cs b/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.cs index f16dd70d0..298ff2ead 100644 --- a/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.cs +++ b/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.cs @@ -2,1479 +2,1478 @@ using MessagePack; using MessagePack.Formatters; -namespace MagicOnion.Serialization.MessagePack +namespace MagicOnion.Serialization.MessagePack; + +// T2 ~ T15 +// NOTE: Blazor WebAssembly (AOT) does not support more than 16 generic type parameters. + + +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> { - // T2 ~ T15 - // NOTE: Blazor WebAssembly (AOT) does not support more than 16 generic type parameters. + readonly T1 default1; + readonly T2 default2; + public DynamicArgumentTupleFormatter() + { + this.default1 = default!; + this.default2 = default!; + } - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> + public DynamicArgumentTupleFormatter(T1 default1, T2 default2) { - readonly T1 default1; - readonly T2 default2; + this.default1 = default1; + this.default2 = default2; + } - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(2); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2) - { - this.default1 = default1; - this.default2 = default2; - } + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); + + var item1 = default1; + var item2 = default2; - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + for (var i = 0; i < length; i++) { - writer.WriteArrayHeader(2); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + switch (i) + { + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; + } } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) - { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); + return new DynamicArgumentTuple(item1, item2); + } +} - var item1 = default1; - var item2 = default2; +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; - for (var i = 0; i < length; i++) - { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } - } + public DynamicArgumentTupleFormatter() + { + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + } - return new DynamicArgumentTuple(item1, item2); - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; } - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; + writer.WriteArrayHeader(3); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + } - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - } + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - } + var item1 = default1; + var item2 = default2; + var item3 = default3; - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + for (var i = 0; i < length; i++) { - writer.WriteArrayHeader(3); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + switch (i) + { + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; + } } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) - { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); + return new DynamicArgumentTuple(item1, item2, item3); + } +} - var item1 = default1; - var item2 = default2; - var item3 = default3; +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; - for (var i = 0; i < length; i++) - { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } - } + public DynamicArgumentTupleFormatter() + { + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + } - return new DynamicArgumentTuple(item1, item2, item3); - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; } - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; + writer.WriteArrayHeader(4); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + } - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - } + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - } + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + for (var i = 0; i < length; i++) { - writer.WriteArrayHeader(4); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + switch (i) + { + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; + } } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) - { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; + return new DynamicArgumentTuple(item1, item2, item3, item4); + } +} - for (var i = 0; i < length; i++) - { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } - } +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; - return new DynamicArgumentTuple(item1, item2, item3, item4); - } + public DynamicArgumentTupleFormatter() + { + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; } - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5) { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + } - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(5); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - } + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(5); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - } + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + for (var i = 0; i < length; i++) { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - - for (var i = 0; i < length; i++) + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5); } +} - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; + readonly T6 default6; + + public DynamicArgumentTupleFormatter() { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; - readonly T6 default6; - - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - this.default6 = default!; - } + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; + this.default6 = default!; + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - this.default6 = default6; - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + this.default6 = default6; + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(6); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(6); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); + } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) - { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - var item6 = default6; + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; + var item6 = default6; - for (var i = 0; i < length; i++) + for (var i = 0; i < length; i++) + { + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 5: - item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 5: + item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6); } +} - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; + readonly T6 default6; + readonly T7 default7; + + public DynamicArgumentTupleFormatter() { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; - readonly T6 default6; - readonly T7 default7; - - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - this.default6 = default!; - this.default7 = default!; - } + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; + this.default6 = default!; + this.default7 = default!; + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - this.default6 = default6; - this.default7 = default7; - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + this.default6 = default6; + this.default7 = default7; + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(7); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(7); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); + } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); + + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; + var item6 = default6; + var item7 = default7; + + for (var i = 0; i < length; i++) { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - var item6 = default6; - var item7 = default7; - - for (var i = 0; i < length; i++) + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 5: - item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 6: - item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 5: + item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 6: + item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7); } +} - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; + readonly T6 default6; + readonly T7 default7; + readonly T8 default8; + + public DynamicArgumentTupleFormatter() { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; - readonly T6 default6; - readonly T7 default7; - readonly T8 default8; - - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - this.default6 = default!; - this.default7 = default!; - this.default8 = default!; - } + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; + this.default6 = default!; + this.default7 = default!; + this.default8 = default!; + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - this.default6 = default6; - this.default7 = default7; - this.default8 = default8; - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + this.default6 = default6; + this.default7 = default7; + this.default8 = default8; + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(8); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(8); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); + } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); + + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; + var item6 = default6; + var item7 = default7; + var item8 = default8; + + for (var i = 0; i < length; i++) { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - var item6 = default6; - var item7 = default7; - var item8 = default8; - - for (var i = 0; i < length; i++) + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 5: - item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 6: - item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 7: - item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 5: + item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 6: + item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 7: + item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8); } +} - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; + readonly T6 default6; + readonly T7 default7; + readonly T8 default8; + readonly T9 default9; + + public DynamicArgumentTupleFormatter() { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; - readonly T6 default6; - readonly T7 default7; - readonly T8 default8; - readonly T9 default9; - - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - this.default6 = default!; - this.default7 = default!; - this.default8 = default!; - this.default9 = default!; - } + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; + this.default6 = default!; + this.default7 = default!; + this.default8 = default!; + this.default9 = default!; + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - this.default6 = default6; - this.default7 = default7; - this.default8 = default8; - this.default9 = default9; - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + this.default6 = default6; + this.default7 = default7; + this.default8 = default8; + this.default9 = default9; + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(9); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(9); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); + } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); + + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; + var item6 = default6; + var item7 = default7; + var item8 = default8; + var item9 = default9; + + for (var i = 0; i < length; i++) { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - var item6 = default6; - var item7 = default7; - var item8 = default8; - var item9 = default9; - - for (var i = 0; i < length; i++) + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 5: - item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 6: - item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 7: - item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 8: - item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 5: + item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 6: + item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 7: + item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 8: + item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9); } +} - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; + readonly T6 default6; + readonly T7 default7; + readonly T8 default8; + readonly T9 default9; + readonly T10 default10; + + public DynamicArgumentTupleFormatter() { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; - readonly T6 default6; - readonly T7 default7; - readonly T8 default8; - readonly T9 default9; - readonly T10 default10; - - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - this.default6 = default!; - this.default7 = default!; - this.default8 = default!; - this.default9 = default!; - this.default10 = default!; - } + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; + this.default6 = default!; + this.default7 = default!; + this.default8 = default!; + this.default9 = default!; + this.default10 = default!; + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - this.default6 = default6; - this.default7 = default7; - this.default8 = default8; - this.default9 = default9; - this.default10 = default10; - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + this.default6 = default6; + this.default7 = default7; + this.default8 = default8; + this.default9 = default9; + this.default10 = default10; + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(10); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(10); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); + } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); + + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; + var item6 = default6; + var item7 = default7; + var item8 = default8; + var item9 = default9; + var item10 = default10; + + for (var i = 0; i < length; i++) { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - var item6 = default6; - var item7 = default7; - var item8 = default8; - var item9 = default9; - var item10 = default10; - - for (var i = 0; i < length; i++) + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 5: - item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 6: - item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 7: - item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 8: - item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 9: - item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 5: + item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 6: + item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 7: + item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 8: + item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 9: + item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10); } +} - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; + readonly T6 default6; + readonly T7 default7; + readonly T8 default8; + readonly T9 default9; + readonly T10 default10; + readonly T11 default11; + + public DynamicArgumentTupleFormatter() { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; - readonly T6 default6; - readonly T7 default7; - readonly T8 default8; - readonly T9 default9; - readonly T10 default10; - readonly T11 default11; - - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - this.default6 = default!; - this.default7 = default!; - this.default8 = default!; - this.default9 = default!; - this.default10 = default!; - this.default11 = default!; - } + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; + this.default6 = default!; + this.default7 = default!; + this.default8 = default!; + this.default9 = default!; + this.default10 = default!; + this.default11 = default!; + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10, T11 default11) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - this.default6 = default6; - this.default7 = default7; - this.default8 = default8; - this.default9 = default9; - this.default10 = default10; - this.default11 = default11; - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10, T11 default11) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + this.default6 = default6; + this.default7 = default7; + this.default8 = default8; + this.default9 = default9; + this.default10 = default10; + this.default11 = default11; + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(11); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item11, options); - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(11); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item11, options); + } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); + + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; + var item6 = default6; + var item7 = default7; + var item8 = default8; + var item9 = default9; + var item10 = default10; + var item11 = default11; + + for (var i = 0; i < length; i++) { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - var item6 = default6; - var item7 = default7; - var item8 = default8; - var item9 = default9; - var item10 = default10; - var item11 = default11; - - for (var i = 0; i < length; i++) + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 5: - item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 6: - item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 7: - item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 8: - item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 9: - item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 10: - item11 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 5: + item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 6: + item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 7: + item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 8: + item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 9: + item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 10: + item11 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11); } +} - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; + readonly T6 default6; + readonly T7 default7; + readonly T8 default8; + readonly T9 default9; + readonly T10 default10; + readonly T11 default11; + readonly T12 default12; + + public DynamicArgumentTupleFormatter() { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; - readonly T6 default6; - readonly T7 default7; - readonly T8 default8; - readonly T9 default9; - readonly T10 default10; - readonly T11 default11; - readonly T12 default12; - - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - this.default6 = default!; - this.default7 = default!; - this.default8 = default!; - this.default9 = default!; - this.default10 = default!; - this.default11 = default!; - this.default12 = default!; - } + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; + this.default6 = default!; + this.default7 = default!; + this.default8 = default!; + this.default9 = default!; + this.default10 = default!; + this.default11 = default!; + this.default12 = default!; + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10, T11 default11, T12 default12) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - this.default6 = default6; - this.default7 = default7; - this.default8 = default8; - this.default9 = default9; - this.default10 = default10; - this.default11 = default11; - this.default12 = default12; - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10, T11 default11, T12 default12) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + this.default6 = default6; + this.default7 = default7; + this.default8 = default8; + this.default9 = default9; + this.default10 = default10; + this.default11 = default11; + this.default12 = default12; + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(12); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item11, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item12, options); - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(12); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item11, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item12, options); + } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); + + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; + var item6 = default6; + var item7 = default7; + var item8 = default8; + var item9 = default9; + var item10 = default10; + var item11 = default11; + var item12 = default12; + + for (var i = 0; i < length; i++) { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - var item6 = default6; - var item7 = default7; - var item8 = default8; - var item9 = default9; - var item10 = default10; - var item11 = default11; - var item12 = default12; - - for (var i = 0; i < length; i++) + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 5: - item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 6: - item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 7: - item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 8: - item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 9: - item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 10: - item11 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 11: - item12 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 5: + item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 6: + item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 7: + item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 8: + item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 9: + item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 10: + item11 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 11: + item12 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12); } +} - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; + readonly T6 default6; + readonly T7 default7; + readonly T8 default8; + readonly T9 default9; + readonly T10 default10; + readonly T11 default11; + readonly T12 default12; + readonly T13 default13; + + public DynamicArgumentTupleFormatter() { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; - readonly T6 default6; - readonly T7 default7; - readonly T8 default8; - readonly T9 default9; - readonly T10 default10; - readonly T11 default11; - readonly T12 default12; - readonly T13 default13; - - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - this.default6 = default!; - this.default7 = default!; - this.default8 = default!; - this.default9 = default!; - this.default10 = default!; - this.default11 = default!; - this.default12 = default!; - this.default13 = default!; - } + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; + this.default6 = default!; + this.default7 = default!; + this.default8 = default!; + this.default9 = default!; + this.default10 = default!; + this.default11 = default!; + this.default12 = default!; + this.default13 = default!; + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10, T11 default11, T12 default12, T13 default13) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - this.default6 = default6; - this.default7 = default7; - this.default8 = default8; - this.default9 = default9; - this.default10 = default10; - this.default11 = default11; - this.default12 = default12; - this.default13 = default13; - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10, T11 default11, T12 default12, T13 default13) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + this.default6 = default6; + this.default7 = default7; + this.default8 = default8; + this.default9 = default9; + this.default10 = default10; + this.default11 = default11; + this.default12 = default12; + this.default13 = default13; + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(13); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item11, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item12, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item13, options); - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(13); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item11, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item12, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item13, options); + } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); + + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; + var item6 = default6; + var item7 = default7; + var item8 = default8; + var item9 = default9; + var item10 = default10; + var item11 = default11; + var item12 = default12; + var item13 = default13; + + for (var i = 0; i < length; i++) { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - var item6 = default6; - var item7 = default7; - var item8 = default8; - var item9 = default9; - var item10 = default10; - var item11 = default11; - var item12 = default12; - var item13 = default13; - - for (var i = 0; i < length; i++) + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 5: - item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 6: - item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 7: - item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 8: - item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 9: - item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 10: - item11 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 11: - item12 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 12: - item13 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 5: + item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 6: + item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 7: + item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 8: + item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 9: + item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 10: + item11 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 11: + item12 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 12: + item13 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13); } +} - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; + readonly T6 default6; + readonly T7 default7; + readonly T8 default8; + readonly T9 default9; + readonly T10 default10; + readonly T11 default11; + readonly T12 default12; + readonly T13 default13; + readonly T14 default14; + + public DynamicArgumentTupleFormatter() { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; - readonly T6 default6; - readonly T7 default7; - readonly T8 default8; - readonly T9 default9; - readonly T10 default10; - readonly T11 default11; - readonly T12 default12; - readonly T13 default13; - readonly T14 default14; - - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - this.default6 = default!; - this.default7 = default!; - this.default8 = default!; - this.default9 = default!; - this.default10 = default!; - this.default11 = default!; - this.default12 = default!; - this.default13 = default!; - this.default14 = default!; - } + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; + this.default6 = default!; + this.default7 = default!; + this.default8 = default!; + this.default9 = default!; + this.default10 = default!; + this.default11 = default!; + this.default12 = default!; + this.default13 = default!; + this.default14 = default!; + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10, T11 default11, T12 default12, T13 default13, T14 default14) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - this.default6 = default6; - this.default7 = default7; - this.default8 = default8; - this.default9 = default9; - this.default10 = default10; - this.default11 = default11; - this.default12 = default12; - this.default13 = default13; - this.default14 = default14; - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10, T11 default11, T12 default12, T13 default13, T14 default14) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + this.default6 = default6; + this.default7 = default7; + this.default8 = default8; + this.default9 = default9; + this.default10 = default10; + this.default11 = default11; + this.default12 = default12; + this.default13 = default13; + this.default14 = default14; + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(14); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item11, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item12, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item13, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item14, options); - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(14); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item11, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item12, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item13, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item14, options); + } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); + + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; + var item6 = default6; + var item7 = default7; + var item8 = default8; + var item9 = default9; + var item10 = default10; + var item11 = default11; + var item12 = default12; + var item13 = default13; + var item14 = default14; + + for (var i = 0; i < length; i++) { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - var item6 = default6; - var item7 = default7; - var item8 = default8; - var item9 = default9; - var item10 = default10; - var item11 = default11; - var item12 = default12; - var item13 = default13; - var item14 = default14; - - for (var i = 0; i < length; i++) + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 5: - item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 6: - item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 7: - item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 8: - item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 9: - item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 10: - item11 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 11: - item12 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 12: - item13 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 13: - item14 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 5: + item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 6: + item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 7: + item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 8: + item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 9: + item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 10: + item11 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 11: + item12 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 12: + item13 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 13: + item14 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14); } +} - public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +public class DynamicArgumentTupleFormatter : IMessagePackFormatter> +{ + readonly T1 default1; + readonly T2 default2; + readonly T3 default3; + readonly T4 default4; + readonly T5 default5; + readonly T6 default6; + readonly T7 default7; + readonly T8 default8; + readonly T9 default9; + readonly T10 default10; + readonly T11 default11; + readonly T12 default12; + readonly T13 default13; + readonly T14 default14; + readonly T15 default15; + + public DynamicArgumentTupleFormatter() { - readonly T1 default1; - readonly T2 default2; - readonly T3 default3; - readonly T4 default4; - readonly T5 default5; - readonly T6 default6; - readonly T7 default7; - readonly T8 default8; - readonly T9 default9; - readonly T10 default10; - readonly T11 default11; - readonly T12 default12; - readonly T13 default13; - readonly T14 default14; - readonly T15 default15; - - public DynamicArgumentTupleFormatter() - { - this.default1 = default!; - this.default2 = default!; - this.default3 = default!; - this.default4 = default!; - this.default5 = default!; - this.default6 = default!; - this.default7 = default!; - this.default8 = default!; - this.default9 = default!; - this.default10 = default!; - this.default11 = default!; - this.default12 = default!; - this.default13 = default!; - this.default14 = default!; - this.default15 = default!; - } + this.default1 = default!; + this.default2 = default!; + this.default3 = default!; + this.default4 = default!; + this.default5 = default!; + this.default6 = default!; + this.default7 = default!; + this.default8 = default!; + this.default9 = default!; + this.default10 = default!; + this.default11 = default!; + this.default12 = default!; + this.default13 = default!; + this.default14 = default!; + this.default15 = default!; + } - public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10, T11 default11, T12 default12, T13 default13, T14 default14, T15 default15) - { - this.default1 = default1; - this.default2 = default2; - this.default3 = default3; - this.default4 = default4; - this.default5 = default5; - this.default6 = default6; - this.default7 = default7; - this.default8 = default8; - this.default9 = default9; - this.default10 = default10; - this.default11 = default11; - this.default12 = default12; - this.default13 = default13; - this.default14 = default14; - this.default15 = default15; - } + public DynamicArgumentTupleFormatter(T1 default1, T2 default2, T3 default3, T4 default4, T5 default5, T6 default6, T7 default7, T8 default8, T9 default9, T10 default10, T11 default11, T12 default12, T13 default13, T14 default14, T15 default15) + { + this.default1 = default1; + this.default2 = default2; + this.default3 = default3; + this.default4 = default4; + this.default5 = default5; + this.default6 = default6; + this.default7 = default7; + this.default8 = default8; + this.default9 = default9; + this.default10 = default10; + this.default11 = default11; + this.default12 = default12; + this.default13 = default13; + this.default14 = default14; + this.default15 = default15; + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(15); - var resolver = options.Resolver; - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item11, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item12, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item13, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item14, options); - resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item15, options); - } + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(15); + var resolver = options.Resolver; + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item1, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item2, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item3, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item4, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item5, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item6, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item7, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item8, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item9, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item10, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item11, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item12, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item13, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item14, options); + resolver.GetFormatterWithVerify().Serialize(ref writer, value.Item15, options); + } - public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + public DynamicArgumentTuple Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); + + var item1 = default1; + var item2 = default2; + var item3 = default3; + var item4 = default4; + var item5 = default5; + var item6 = default6; + var item7 = default7; + var item8 = default8; + var item9 = default9; + var item10 = default10; + var item11 = default11; + var item12 = default12; + var item13 = default13; + var item14 = default14; + var item15 = default15; + + for (var i = 0; i < length; i++) { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); - - var item1 = default1; - var item2 = default2; - var item3 = default3; - var item4 = default4; - var item5 = default5; - var item6 = default6; - var item7 = default7; - var item8 = default8; - var item9 = default9; - var item10 = default10; - var item11 = default11; - var item12 = default12; - var item13 = default13; - var item14 = default14; - var item15 = default15; - - for (var i = 0; i < length; i++) + switch (i) { - switch (i) - { - case 0: - item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 1: - item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 2: - item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 3: - item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 4: - item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 5: - item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 6: - item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 7: - item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 8: - item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 9: - item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 10: - item11 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 11: - item12 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 12: - item13 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 13: - item14 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - case 14: - item15 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); - break; - default: - reader.Skip(); - break; - } + case 0: + item1 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 1: + item2 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 2: + item3 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 3: + item4 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 4: + item5 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 5: + item6 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 6: + item7 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 7: + item8 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 8: + item9 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 9: + item10 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 10: + item11 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 11: + item12 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 12: + item13 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 13: + item14 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + case 14: + item15 = resolver.GetFormatterWithVerify().Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15); } + + return new DynamicArgumentTuple(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15); } } diff --git a/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.tt b/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.tt index 54097a0ae..6091e9777 100644 --- a/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.tt +++ b/src/MagicOnion.Serialization.MessagePack/DynamicArgumentTupleFormatter.tt @@ -9,10 +9,10 @@ using MessagePack; using MessagePack.Formatters; -namespace MagicOnion.Serialization.MessagePack -{ - // T2 ~ T15 - // NOTE: Blazor WebAssembly (AOT) does not support more than 16 generic type parameters. +namespace MagicOnion.Serialization.MessagePack; + +// T2 ~ T15 +// NOTE: Blazor WebAssembly (AOT) does not support more than 16 generic type parameters. <# for(var i = 2; i <= 15; i++) { var typeArgs = string.Join(", ", Enumerable.Range(1, i).Select(x => string.Format("T{0}", x))); @@ -21,61 +21,60 @@ namespace MagicOnion.Serialization.MessagePack var itemArgs = string.Join(", ", Enumerable.Range(1, i).Select(x => string.Format("item{0}", x))); #> - public class DynamicArgumentTupleFormatter<<#= typeArgs #>> : IMessagePackFormatter>> - { +public class DynamicArgumentTupleFormatter<<#= typeArgs #>> : IMessagePackFormatter>> +{ <# for(var j = 1; j <= i; j++) { #> - readonly T<#= j #> default<#= j #>; + readonly T<#= j #> default<#= j #>; <# } #> - public DynamicArgumentTupleFormatter() - { + public DynamicArgumentTupleFormatter() + { <# for(var j = 1; j <= i; j++) { #> - this.default<#= j #> = default!; + this.default<#= j #> = default!; <# } #> - } + } - public DynamicArgumentTupleFormatter(<#= defaultArgs #>) - { + public DynamicArgumentTupleFormatter(<#= defaultArgs #>) + { <# for(var j = 1; j <= i; j++) { #> - this.default<#= j #> = default<#= j #>; + this.default<#= j #> = default<#= j #>; <# } #> - } + } - public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple<<#= typeArgs #>> value, MessagePackSerializerOptions options) - { - writer.WriteArrayHeader(<#= i #>); - var resolver = options.Resolver; + public void Serialize(ref MessagePackWriter writer, DynamicArgumentTuple<<#= typeArgs #>> value, MessagePackSerializerOptions options) + { + writer.WriteArrayHeader(<#= i #>); + var resolver = options.Resolver; <# for(var j = 1; j <= i; j++) { #> - resolver.GetFormatterWithVerify>().Serialize(ref writer, value.Item<#= j #>, options); + resolver.GetFormatterWithVerify>().Serialize(ref writer, value.Item<#= j #>, options); <# } #> - } + } - public DynamicArgumentTuple<<#= typeArgs #>> Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) - { - var resolver = options.Resolver; - var length = reader.ReadArrayHeader(); + public DynamicArgumentTuple<<#= typeArgs #>> Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + var resolver = options.Resolver; + var length = reader.ReadArrayHeader(); <# for(var j = 1; j <= i; j++) { #> - var item<#= j #> = default<#= j #>; + var item<#= j #> = default<#= j #>; <# } #> - for (var i = 0; i < length; i++) + for (var i = 0; i < length; i++) + { + switch (i) { - switch (i) - { <# for(var j = 1; j <= i; j++) { #> - case <#= j - 1 #>: - item<#= j #> = resolver.GetFormatterWithVerify>().Deserialize(ref reader, options); - break; + case <#= j - 1 #>: + item<#= j #> = resolver.GetFormatterWithVerify>().Deserialize(ref reader, options); + break; <# } #> - default: - reader.Skip(); - break; - } + default: + reader.Skip(); + break; } - - return new DynamicArgumentTuple<<#= typeArgs #>>(<#= itemArgs #>); } + + return new DynamicArgumentTuple<<#= typeArgs #>>(<#= itemArgs #>); } -<# } #> } +<# } #> diff --git a/src/MagicOnion.Shared/MetadataExtensions.cs b/src/MagicOnion.Shared/MetadataExtensions.cs index 5815dbc10..2b633ba00 100644 --- a/src/MagicOnion.Shared/MetadataExtensions.cs +++ b/src/MagicOnion.Shared/MetadataExtensions.cs @@ -1,61 +1,60 @@ using Grpc.Core; -namespace MagicOnion +namespace MagicOnion; + +public static class MetadataExtensions { - public static class MetadataExtensions - { - public const string BinarySuffix = "-bin"; + public const string BinarySuffix = "-bin"; - /// - /// Get metdata entry. If does not exists, return null. - /// - public static Metadata.Entry? GetOrDefault(this Metadata metadata, string key, bool ignoreCase = true) + /// + /// Get metdata entry. If does not exists, return null. + /// + public static Metadata.Entry? GetOrDefault(this Metadata metadata, string key, bool ignoreCase = true) + { + for (int i = 0; i < metadata.Count; i++) { - for (int i = 0; i < metadata.Count; i++) + var entry = metadata[i]; + if (ignoreCase) { - var entry = metadata[i]; - if (ignoreCase) + if (entry.Key.Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (entry.Key.Equals(key, StringComparison.OrdinalIgnoreCase)) - { - return entry; - } + return entry; } - else + } + else + { + if (entry.Key == key) { - if (entry.Key == key) - { - return entry; - } + return entry; } } - return null; } + return null; + } - /// - /// Get metdata string value. If does not exists, return null. - /// - public static string? GetValueOrDefault(this Metadata metadata, string key, bool ignoreCase = true) + /// + /// Get metdata string value. If does not exists, return null. + /// + public static string? GetValueOrDefault(this Metadata metadata, string key, bool ignoreCase = true) + { + for (int i = 0; i < metadata.Count; i++) { - for (int i = 0; i < metadata.Count; i++) + var entry = metadata[i]; + if (ignoreCase) { - var entry = metadata[i]; - if (ignoreCase) + if (entry.Key.Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (entry.Key.Equals(key, StringComparison.OrdinalIgnoreCase)) - { - return entry.Value; - } + return entry.Value; } - else + } + else + { + if (entry.Key == key) { - if (entry.Key == key) - { - return entry.Value; - } + return entry.Value; } } - return null; } + return null; } } diff --git a/src/MagicOnion.Shared/Serialization/MagicOnionSerializer.cs b/src/MagicOnion.Shared/Serialization/MagicOnionSerializer.cs index aae908325..03b686194 100644 --- a/src/MagicOnion.Shared/Serialization/MagicOnionSerializer.cs +++ b/src/MagicOnion.Shared/Serialization/MagicOnionSerializer.cs @@ -1,15 +1,14 @@ using MagicOnion.Serialization.MessagePack; -namespace MagicOnion.Serialization +namespace MagicOnion.Serialization; + +/// +/// Provides a serializer for request/response of MagicOnion services and hub methods. +/// +public static class MagicOnionSerializerProvider { /// - /// Provides a serializer for request/response of MagicOnion services and hub methods. + /// Gets or sets the to be used by default. /// - public static class MagicOnionSerializerProvider - { - /// - /// Gets or sets the to be used by default. - /// - public static IMagicOnionSerializerProvider Default { get; set; } = MessagePackMagicOnionSerializerProvider.Default; - } + public static IMagicOnionSerializerProvider Default { get; set; } = MessagePackMagicOnionSerializerProvider.Default; }