diff --git a/samples/ChatApp/ChatApp.Console/ChatApp.Console.csproj b/samples/ChatApp/ChatApp.Console/ChatApp.Console.csproj
index aafa3e639..0dc2bb1c2 100644
--- a/samples/ChatApp/ChatApp.Console/ChatApp.Console.csproj
+++ b/samples/ChatApp/ChatApp.Console/ChatApp.Console.csproj
@@ -5,8 +5,14 @@
net8.0
enable
enable
+ true
+ true
+
+
+
+
diff --git a/samples/ChatApp/ChatApp.Console/Program.cs b/samples/ChatApp/ChatApp.Console/Program.cs
index 71c1c4429..e6baae822 100644
--- a/samples/ChatApp/ChatApp.Console/Program.cs
+++ b/samples/ChatApp/ChatApp.Console/Program.cs
@@ -1,12 +1,26 @@
// See https://aka.ms/new-console-template for more information
+using System.Runtime.CompilerServices;
using ChatApp.Shared.Hubs;
using ChatApp.Shared.MessagePackObjects;
using Grpc.Net.Client;
using MagicOnion.Client;
+using MessagePack;
+using MessagePack.Resolvers;
-var channel = GrpcChannel.ForAddress("http://localhost:5000");
+if (!RuntimeFeature.IsDynamicCodeSupported)
+{
+ // Running on Native AOT
+ StaticCompositeResolver.Instance.Register(
+ BuiltinResolver.Instance,
+ PrimitiveObjectResolver.Instance,
+ MagicOnionGeneratedClientInitializer.Resolver,
+ MessagePack.Resolvers.GeneratedResolver.Instance
+ );
+ MessagePackSerializer.DefaultOptions = MessagePackSerializer.DefaultOptions.WithResolver(StaticCompositeResolver.Instance);
+}
+var channel = GrpcChannel.ForAddress("http://localhost:5000");
var sessionId = Guid.NewGuid();
Console.WriteLine("Connecting...");
var hub = await StreamingHubClient.ConnectAsync(channel, new ChatHubReceiver(sessionId));
@@ -30,7 +44,6 @@
[MagicOnionClientGeneration(typeof(IChatHub))]
partial class MagicOnionGeneratedClientInitializer;
-
class ChatHubReceiver(Guid sessionId) : IChatHubReceiver
{
public void OnJoin(string name)
diff --git a/src/MagicOnion.Abstractions/Internal/Box.cs b/src/MagicOnion.Abstractions/Internal/Box.cs
index 3a0acc1a4..63b6db870 100644
--- a/src/MagicOnion.Abstractions/Internal/Box.cs
+++ b/src/MagicOnion.Abstractions/Internal/Box.cs
@@ -18,21 +18,21 @@ internal Box(T value)
Value = value;
}
- public bool Equals(Box other)
+ 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)
+ 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);
+ return EqualityComparer.Default.GetHashCode(Value!);
}
public static bool operator ==(Box valueA, Box valueB)
diff --git a/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj b/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj
index 748f240b8..bc66af320 100644
--- a/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj
+++ b/src/MagicOnion.Abstractions/MagicOnion.Abstractions.csproj
@@ -1,10 +1,11 @@
- netstandard2.0
+ netstandard2.0;net8.0
$(_LangVersionUnityBaseline)
enable
+ true
MagicOnion.Abstractions
MagicOnion interfaces and abstractions for server and client.
diff --git a/src/MagicOnion.Abstractions/PublicAPI.Shipped.txt b/src/MagicOnion.Abstractions/PublicAPI.Shipped.txt
index 31e7e16d6..c7261b555 100644
--- a/src/MagicOnion.Abstractions/PublicAPI.Shipped.txt
+++ b/src/MagicOnion.Abstractions/PublicAPI.Shipped.txt
@@ -90,7 +90,7 @@ MagicOnion.IgnoreAttribute
MagicOnion.IgnoreAttribute.IgnoreAttribute() -> void
MagicOnion.Internal.Box
MagicOnion.Internal.Box
-MagicOnion.Internal.Box.Equals(MagicOnion.Internal.Box! other) -> bool
+MagicOnion.Internal.Box.Equals(MagicOnion.Internal.Box? other) -> bool
MagicOnion.Internal.IAsyncClientStreamingCallWrapper
MagicOnion.Internal.IAsyncClientStreamingCallWrapper.RequestStream.get -> Grpc.Core.IClientStreamWriter!
MagicOnion.Internal.IAsyncClientStreamingCallWrapper.ResponseAsync.get -> System.Threading.Tasks.Task!
@@ -155,7 +155,7 @@ MagicOnion.UnaryResult.UnaryResult() -> void
MagicOnion.UnaryResult.UnaryResult(System.Threading.Tasks.Task!>! response) -> void
MagicOnion.UnaryResult.UnaryResult(System.Threading.Tasks.Task! rawTaskValue) -> void
MagicOnion.UnaryResult.UnaryResult(TResponse rawValue) -> void
-override MagicOnion.Internal.Box.Equals(object! obj) -> bool
+override MagicOnion.Internal.Box.Equals(object? obj) -> bool
override MagicOnion.Internal.Box.GetHashCode() -> int
readonly MagicOnion.DynamicArgumentTuple.Item1 -> T1
readonly MagicOnion.DynamicArgumentTuple.Item10 -> T10
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Abstractions/Internal/Box.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Abstractions/Internal/Box.cs
index 3a0acc1a4..63b6db870 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Abstractions/Internal/Box.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Abstractions/Internal/Box.cs
@@ -18,21 +18,21 @@ internal Box(T value)
Value = value;
}
- public bool Equals(Box other)
+ 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)
+ 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);
+ return EqualityComparer.Default.GetHashCode(Value!);
}
public static bool operator ==(Box valueA, Box valueB)
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs
index 119ec5f69..3c0343c02 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs
@@ -1,7 +1,9 @@
+using System.Diagnostics.CodeAnalysis;
using MagicOnion.Internal.Reflection;
namespace MagicOnion.Client.DynamicClient
{
+ [RequiresUnreferencedCode(nameof(DynamicClientAssemblyHolder) + " is incompatible with trimming and Native AOT.")]
#if ENABLE_SAVE_ASSEMBLY
public
#else
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs
index 4e5193192..7be683746 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
-using System.Text;
using Grpc.Core;
using MagicOnion.Client.Internal;
using MagicOnion.Serialization;
@@ -20,6 +20,7 @@ protected static class KnownTypes
}
}
+ [RequiresUnreferencedCode(nameof(DynamicClientBuilder) + " is incompatible with trimming and Native AOT.")]
internal class DynamicClientBuilder : DynamicClientBuilder
where T : IService
{
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs
index fefc4c174..47a7d3d42 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs
@@ -18,6 +18,7 @@ public bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDele
///
/// 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();
@@ -30,6 +31,7 @@ public bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDele
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
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs
index 09d4d4355..9173e8f06 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs
@@ -6,6 +6,7 @@
using MessagePack;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
@@ -14,6 +15,7 @@
namespace MagicOnion.Client.DynamicClient
{
+ [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientAssemblyHolder) + " is incompatible with trimming and Native AOT.")]
#if ENABLE_SAVE_ASSEMBLY
public
#else
@@ -41,6 +43,7 @@ public static AssemblyBuilder Save()
#endif
}
+ [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientBuilder) + " is incompatible with trimming and Native AOT.")]
#if ENABLE_SAVE_ASSEMBLY
public
#else
@@ -709,6 +712,7 @@ static void DefineMethodsFireAndForget(TypeBuilder typeBuilder, Type interfaceTy
}
}
+ [RequiresUnreferencedCode(nameof(MethodInfoCache) + " is incompatible with trimming and Native AOT.")]
static class MethodInfoCache
{
// ReSharper disable StaticMemberInGenericType
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs
index 0f1d0c53a..d6ee35879 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs
@@ -15,6 +15,7 @@ public bool TryGetFactory([NotNullWhen(true)] out Stre
}
}
+ [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientFactoryProvider) + " is incompatible with trimming and Native AOT.")]
public class DynamicStreamingHubClientFactoryProvider : IStreamingHubClientFactoryProvider
{
public static IStreamingHubClientFactoryProvider Instance { get; } = new DynamicStreamingHubClientFactoryProvider();
@@ -27,6 +28,7 @@ public bool TryGetFactory([NotNullWhen(true)] out Stre
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
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs
index 74499020b..80a85c9b3 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs
@@ -1,10 +1,11 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
-using Grpc.Core;
using MagicOnion.Client.Internal;
namespace MagicOnion.Client.DynamicClient
{
+ [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)!;
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs
index 94b8c361d..8e4519d22 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
@@ -9,6 +10,7 @@
namespace MagicOnion.Client.DynamicClient
{
+ [RequiresUnreferencedCode(nameof(ServiceClientDefinition) + " is incompatible with trimming and Native AOT.")]
internal class ServiceClientDefinition
{
public Type ServiceInterfaceType { get; }
@@ -20,6 +22,7 @@ public ServiceClientDefinition(Type serviceInterfaceType, IReadOnlyList()
return new ServiceClientDefinition(typeof(T), GetServiceMethods(typeof(T)));
}
- private static IReadOnlyList GetServiceMethods(Type serviceType)
+ static IReadOnlyList GetServiceMethods(Type serviceType)
{
return serviceType
.GetInterfaces()
@@ -209,7 +212,7 @@ private static IReadOnlyList GetServiceMethods(Type
///
///
///
- private static Type GetRequestTypeFromMethod(MethodInfo methodInfo)
+ static Type GetRequestTypeFromMethod(MethodInfo methodInfo)
{
var parameterTypes = methodInfo.GetParameters().Select(x => x.ParameterType).ToArray();
switch (parameterTypes.Length)
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/BroadcasterHelper.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/BroadcasterHelper.cs
index eab0c5c9d..f87114cb5 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/BroadcasterHelper.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/BroadcasterHelper.cs
@@ -1,11 +1,13 @@
using MagicOnion.Server.Hubs;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
namespace MagicOnion.Internal
{
+ [RequiresUnreferencedCode("BroadcastHelper is incompatible with trimming.")]
internal static class BroadcasterHelper
{
internal static Type[] DynamicArgumentTupleTypes { get; } = typeof(DynamicArgumentTuple<,>)
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/MagicOnionMarshallers.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/MagicOnionMarshallers.cs
index af9233361..33360672c 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/MagicOnionMarshallers.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/MagicOnionMarshallers.cs
@@ -2,6 +2,7 @@
using MessagePack;
using System;
using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
@@ -10,13 +11,7 @@ namespace MagicOnion.Internal
// invoke from dynamic methods so must be public
internal static class MagicOnionMarshallers
{
- static readonly Type[] dynamicArgumentTupleTypes = typeof(DynamicArgumentTuple<,>).GetTypeInfo().Assembly
- .GetTypes()
- .Where(x => x.Name.StartsWith("DynamicArgumentTuple") && !x.Name.Contains("Formatter"))
- .OrderBy(x => x.GetGenericArguments().Length)
- .ToArray();
-
- internal static Marshaller StreamingHubMarshaller { get; } = new(
+ public static Marshaller StreamingHubMarshaller { get; } = new(
serializer: static (payload, context) =>
{
context.SetPayloadLength(payload.Length);
@@ -32,7 +27,8 @@ internal static class MagicOnionMarshallers
}
);
- internal static Type CreateRequestType(ParameterInfo[] parameters)
+ [RequiresUnreferencedCode(nameof(MagicOnionMarshallers) + "." + nameof(CreateRequestType) + " is incompatible with trimming and Native AOT.")]
+ public static Type CreateRequestType(ParameterInfo[] parameters)
{
if (parameters.Length == 0)
{
@@ -50,18 +46,29 @@ internal static Type CreateRequestType(ParameterInfo[] parameters)
else
{
// start from T2
- var tupleTypeBase = dynamicArgumentTupleTypes[parameters.Length - 2];
+ 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 = dynamicArgumentTupleTypes[arguments.Length - 2];
+ 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.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil.meta b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil.meta
new file mode 100644
index 000000000..1fcc953fc
--- /dev/null
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d0740739ff0548f42abb6937a771bcfd
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/RequiresUnreferencedCodeAttribute.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/RequiresUnreferencedCodeAttribute.cs
new file mode 100644
index 000000000..a59a86c95
--- /dev/null
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/RequiresUnreferencedCodeAttribute.cs
@@ -0,0 +1,20 @@
+#if !NET6_0_OR_GREATER
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Diagnostics.CodeAnalysis
+{
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
+ internal class RequiresUnreferencedCodeAttribute : Attribute
+ {
+ public string Message { get; }
+ public string? Url { get; }
+
+ public RequiresUnreferencedCodeAttribute(string message)
+ {
+ Message = message;
+ }
+ }
+}
+#endif
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/RequiresUnreferencedCodeAttribute.cs.meta b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/RequiresUnreferencedCodeAttribute.cs.meta
new file mode 100644
index 000000000..b87290575
--- /dev/null
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/RequiresUnreferencedCodeAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1d0a558474e947549a1d7c4f4455c44c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/UnconditionalSuppressMessageAttribute.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/UnconditionalSuppressMessageAttribute.cs
new file mode 100644
index 000000000..4e5dff129
--- /dev/null
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/UnconditionalSuppressMessageAttribute.cs
@@ -0,0 +1,25 @@
+#if !NET6_0_OR_GREATER
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Diagnostics.CodeAnalysis
+{
+ [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 UnconditionalSuppressMessageAttribute(string category, string checkId)
+ {
+ Category = category;
+ CheckId = checkId;
+ }
+ }
+}
+#endif
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/UnconditionalSuppressMessageAttribute.cs.meta b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/UnconditionalSuppressMessageAttribute.cs.meta
new file mode 100644
index 000000000..5a26a820d
--- /dev/null
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Polyfil/UnconditionalSuppressMessageAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 337e745c02c4896408b607de73abe11b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Reflection/DynamicAssembly.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Reflection/DynamicAssembly.cs
index 83972a8c8..6914ec17f 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Reflection/DynamicAssembly.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal.Shared/Reflection/DynamicAssembly.cs
@@ -1,10 +1,12 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
namespace MagicOnion.Internal.Reflection
{
+ [RequiresUnreferencedCode(nameof(DynamicAssembly) + " is incompatible with trimming and Native AOT.")]
#if ENABLE_SAVE_ASSEMBLY
public
#else
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal/DictionaryExtensions.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal/DictionaryExtensions.cs
index ca34940c8..6ff83e76a 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal/DictionaryExtensions.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/Internal/DictionaryExtensions.cs
@@ -1,3 +1,4 @@
+#if NETSTANDARD2_0
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -8,7 +9,6 @@ namespace System.Collections.Generic
{
internal static class DictionaryExtensions
{
-#if NETSTANDARD2_0
public static bool Remove(this IDictionary dict, TKey key, [NotNullWhen(true)] out TValue? value)
{
if (dict.TryGetValue(key, out var v))
@@ -21,6 +21,6 @@ public static bool Remove(this IDictionary dict, TKe
value = default;
return false;
}
-#endif
}
}
+#endif
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/MagicOnionClientFactoryProvider.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/MagicOnionClientFactoryProvider.cs
index 345cb1f08..10f1365b1 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/MagicOnionClientFactoryProvider.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/MagicOnionClientFactoryProvider.cs
@@ -9,6 +9,7 @@ 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
{
///
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/StreamingHubClientFactoryProvider.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/StreamingHubClientFactoryProvider.cs
index 50f7be83c..63ef1ba01 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/StreamingHubClientFactoryProvider.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Client/StreamingHubClientFactoryProvider.cs
@@ -9,6 +9,7 @@ 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
{
///
diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs
index 76e0e9411..298bb14cc 100644
--- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs
+++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs
@@ -2,6 +2,7 @@
using System.Buffers;
using System.Linq;
using System.Reflection;
+using System.Runtime.CompilerServices;
using Grpc.Core;
using MessagePack;
using MessagePack.Formatters;
@@ -42,26 +43,43 @@ public MessagePackMagicOnionSerializerProvider WithEnableFallback(bool enableFal
return new MessagePackMagicOnionSerializerProvider(SerializerOptions, enableFallback);
}
+
+#if NET6_0_OR_GREATER
+ [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "ClientFactoryProvider is resolved at runtime.")]
+#endif
public IMagicOnionSerializer Create(MethodType methodType, MethodInfo? methodInfo)
{
var serializerOptions = EnableFallback && methodInfo != null ? WrapFallbackResolverIfNeeded(methodInfo.GetParameters()) : SerializerOptions;
return new MessagePackMagicOnionSerializer(serializerOptions);
}
- static readonly Type[] dynamicArgumentTupleTypes = typeof(DynamicArgumentTuple<,>).GetTypeInfo().Assembly
- .GetTypes()
- .Where(x => x.Name.StartsWith("DynamicArgumentTuple") && !x.Name.Contains("Formatter"))
- .OrderBy(x => x.GetGenericArguments().Length)
- .ToArray();
+#if NET6_0_OR_GREATER
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(nameof(DynamicArgumentTupleTypeCache) + " is incompatible with trimming and Native AOT.")]
+#endif
+ static class DynamicArgumentTupleTypeCache
+ {
+ 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();
+
+ public static readonly Type[] FormatterTypes = typeof(DynamicArgumentTupleFormatter<,,>).GetTypeInfo().Assembly
+ .GetTypes()
+ .Where(x => x.Name.StartsWith("DynamicArgumentTupleFormatter"))
+ .OrderBy(x => x.GetGenericArguments().Length)
+ .ToArray();
+ }
- static readonly Type[] dynamicArgumentTupleFormatterTypes = typeof(DynamicArgumentTupleFormatter<,,>).GetTypeInfo().Assembly
- .GetTypes()
- .Where(x => x.Name.StartsWith("DynamicArgumentTupleFormatter"))
- .OrderBy(x => x.GetGenericArguments().Length)
- .ToArray();
+#if NET6_0_OR_GREATER
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(nameof(DynamicArgumentTupleTypeCache) + " is incompatible with trimming and Native AOT.")]
+#endif
MessagePackSerializerOptions WrapFallbackResolverIfNeeded(ParameterInfo[] parameters)
{
+#if !NETSTANDARD2_0
+ if (!RuntimeFeature.IsDynamicCodeSupported) throw new NotSupportedException("When running with AOT runtime, DynamicArgumentTupleFormatter does not support fallback resolver fro optional parameters.");
+#endif
// If the method has no parameter or one parameter, we don't need to create fallback resolver for optional parameters.
if (parameters.Length < 2)
{
@@ -69,8 +87,8 @@ MessagePackSerializerOptions WrapFallbackResolverIfNeeded(ParameterInfo[] parame
}
// start from T2
- var tupleTypeBase = dynamicArgumentTupleTypes[parameters.Length - 2];
- var formatterTypeBase = dynamicArgumentTupleFormatterTypes[parameters.Length - 2];
+ var tupleTypeBase = DynamicArgumentTupleTypeCache.Types[parameters.Length - 2];
+ var formatterTypeBase = DynamicArgumentTupleTypeCache.FormatterTypes[parameters.Length - 2];
var t = tupleTypeBase.MakeGenericType(parameters.Select(x => x.ParameterType).ToArray());
var formatterType = formatterTypeBase.MakeGenericType(parameters.Select(x => x.ParameterType).ToArray());
diff --git a/src/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs b/src/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs
index 119ec5f69..3c0343c02 100644
--- a/src/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs
+++ b/src/MagicOnion.Client/DynamicClient/DynamicClientAssemblyHolder.cs
@@ -1,7 +1,9 @@
+using System.Diagnostics.CodeAnalysis;
using MagicOnion.Internal.Reflection;
namespace MagicOnion.Client.DynamicClient
{
+ [RequiresUnreferencedCode(nameof(DynamicClientAssemblyHolder) + " is incompatible with trimming and Native AOT.")]
#if ENABLE_SAVE_ASSEMBLY
public
#else
diff --git a/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs b/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs
index 4e5193192..7be683746 100644
--- a/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs
+++ b/src/MagicOnion.Client/DynamicClient/DynamicClientBuilder.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
-using System.Text;
using Grpc.Core;
using MagicOnion.Client.Internal;
using MagicOnion.Serialization;
@@ -20,6 +20,7 @@ protected static class KnownTypes
}
}
+ [RequiresUnreferencedCode(nameof(DynamicClientBuilder) + " is incompatible with trimming and Native AOT.")]
internal class DynamicClientBuilder : DynamicClientBuilder
where T : IService
{
diff --git a/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs b/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs
index fefc4c174..47a7d3d42 100644
--- a/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs
+++ b/src/MagicOnion.Client/DynamicClient/DynamicMagicOnionClientFactoryProvider.cs
@@ -18,6 +18,7 @@ public bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDele
///
/// 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();
@@ -30,6 +31,7 @@ public bool TryGetFactory([NotNullWhen(true)] out MagicOnionClientFactoryDele
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
diff --git a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs
index 09d4d4355..9173e8f06 100644
--- a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs
+++ b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientBuilder.cs
@@ -6,6 +6,7 @@
using MessagePack;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
@@ -14,6 +15,7 @@
namespace MagicOnion.Client.DynamicClient
{
+ [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientAssemblyHolder) + " is incompatible with trimming and Native AOT.")]
#if ENABLE_SAVE_ASSEMBLY
public
#else
@@ -41,6 +43,7 @@ public static AssemblyBuilder Save()
#endif
}
+ [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientBuilder) + " is incompatible with trimming and Native AOT.")]
#if ENABLE_SAVE_ASSEMBLY
public
#else
@@ -709,6 +712,7 @@ static void DefineMethodsFireAndForget(TypeBuilder typeBuilder, Type interfaceTy
}
}
+ [RequiresUnreferencedCode(nameof(MethodInfoCache) + " is incompatible with trimming and Native AOT.")]
static class MethodInfoCache
{
// ReSharper disable StaticMemberInGenericType
diff --git a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs
index 0f1d0c53a..d6ee35879 100644
--- a/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs
+++ b/src/MagicOnion.Client/DynamicClient/DynamicStreamingHubClientFactoryProvider.cs
@@ -15,6 +15,7 @@ public bool TryGetFactory([NotNullWhen(true)] out Stre
}
}
+ [RequiresUnreferencedCode(nameof(DynamicStreamingHubClientFactoryProvider) + " is incompatible with trimming and Native AOT.")]
public class DynamicStreamingHubClientFactoryProvider : IStreamingHubClientFactoryProvider
{
public static IStreamingHubClientFactoryProvider Instance { get; } = new DynamicStreamingHubClientFactoryProvider();
@@ -27,6 +28,7 @@ public bool TryGetFactory([NotNullWhen(true)] out Stre
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
diff --git a/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs b/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs
index 74499020b..80a85c9b3 100644
--- a/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs
+++ b/src/MagicOnion.Client/DynamicClient/RawMethodInvokerTypes.cs
@@ -1,10 +1,11 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
-using Grpc.Core;
using MagicOnion.Client.Internal;
namespace MagicOnion.Client.DynamicClient
{
+ [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)!;
diff --git a/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs b/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs
index 94b8c361d..8e4519d22 100644
--- a/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs
+++ b/src/MagicOnion.Client/DynamicClient/ServiceClientDefinition.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
@@ -9,6 +10,7 @@
namespace MagicOnion.Client.DynamicClient
{
+ [RequiresUnreferencedCode(nameof(ServiceClientDefinition) + " is incompatible with trimming and Native AOT.")]
internal class ServiceClientDefinition
{
public Type ServiceInterfaceType { get; }
@@ -20,6 +22,7 @@ public ServiceClientDefinition(Type serviceInterfaceType, IReadOnlyList()
return new ServiceClientDefinition(typeof(T), GetServiceMethods(typeof(T)));
}
- private static IReadOnlyList GetServiceMethods(Type serviceType)
+ static IReadOnlyList GetServiceMethods(Type serviceType)
{
return serviceType
.GetInterfaces()
@@ -209,7 +212,7 @@ private static IReadOnlyList GetServiceMethods(Type
///
///
///
- private static Type GetRequestTypeFromMethod(MethodInfo methodInfo)
+ static Type GetRequestTypeFromMethod(MethodInfo methodInfo)
{
var parameterTypes = methodInfo.GetParameters().Select(x => x.ParameterType).ToArray();
switch (parameterTypes.Length)
diff --git a/src/MagicOnion.Client/Internal/DictionaryExtensions.cs b/src/MagicOnion.Client/Internal/DictionaryExtensions.cs
index ca34940c8..6ff83e76a 100644
--- a/src/MagicOnion.Client/Internal/DictionaryExtensions.cs
+++ b/src/MagicOnion.Client/Internal/DictionaryExtensions.cs
@@ -1,3 +1,4 @@
+#if NETSTANDARD2_0
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -8,7 +9,6 @@ namespace System.Collections.Generic
{
internal static class DictionaryExtensions
{
-#if NETSTANDARD2_0
public static bool Remove(this IDictionary dict, TKey key, [NotNullWhen(true)] out TValue? value)
{
if (dict.TryGetValue(key, out var v))
@@ -21,6 +21,6 @@ public static bool Remove(this IDictionary dict, TKe
value = default;
return false;
}
-#endif
}
}
+#endif
diff --git a/src/MagicOnion.Client/MagicOnion.Client.csproj b/src/MagicOnion.Client/MagicOnion.Client.csproj
index 4afd3dd60..b62cda061 100644
--- a/src/MagicOnion.Client/MagicOnion.Client.csproj
+++ b/src/MagicOnion.Client/MagicOnion.Client.csproj
@@ -5,6 +5,7 @@
$(_LangVersionUnityBaseline)
enable
+ true
MagicOnion.Client
diff --git a/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs b/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs
index 345cb1f08..10f1365b1 100644
--- a/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs
+++ b/src/MagicOnion.Client/MagicOnionClientFactoryProvider.cs
@@ -9,6 +9,7 @@ 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
{
///
diff --git a/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs b/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs
index 50f7be83c..63ef1ba01 100644
--- a/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs
+++ b/src/MagicOnion.Client/StreamingHubClientFactoryProvider.cs
@@ -9,6 +9,7 @@ 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
{
///
diff --git a/src/MagicOnion.Internal/BroadcasterHelper.cs b/src/MagicOnion.Internal/BroadcasterHelper.cs
index eab0c5c9d..f87114cb5 100644
--- a/src/MagicOnion.Internal/BroadcasterHelper.cs
+++ b/src/MagicOnion.Internal/BroadcasterHelper.cs
@@ -1,11 +1,13 @@
using MagicOnion.Server.Hubs;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
namespace MagicOnion.Internal
{
+ [RequiresUnreferencedCode("BroadcastHelper is incompatible with trimming.")]
internal static class BroadcasterHelper
{
internal static Type[] DynamicArgumentTupleTypes { get; } = typeof(DynamicArgumentTuple<,>)
diff --git a/src/MagicOnion.Internal/MagicOnion.Internal.csproj b/src/MagicOnion.Internal/MagicOnion.Internal.csproj
index e6ab71734..fc4b60c88 100644
--- a/src/MagicOnion.Internal/MagicOnion.Internal.csproj
+++ b/src/MagicOnion.Internal/MagicOnion.Internal.csproj
@@ -1,4 +1,4 @@
-
+
netstandard2.0;netstandard2.1;net6.0;net8.0
diff --git a/src/MagicOnion.Internal/MagicOnionMarshallers.cs b/src/MagicOnion.Internal/MagicOnionMarshallers.cs
index af9233361..33360672c 100644
--- a/src/MagicOnion.Internal/MagicOnionMarshallers.cs
+++ b/src/MagicOnion.Internal/MagicOnionMarshallers.cs
@@ -2,6 +2,7 @@
using MessagePack;
using System;
using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
@@ -10,13 +11,7 @@ namespace MagicOnion.Internal
// invoke from dynamic methods so must be public
internal static class MagicOnionMarshallers
{
- static readonly Type[] dynamicArgumentTupleTypes = typeof(DynamicArgumentTuple<,>).GetTypeInfo().Assembly
- .GetTypes()
- .Where(x => x.Name.StartsWith("DynamicArgumentTuple") && !x.Name.Contains("Formatter"))
- .OrderBy(x => x.GetGenericArguments().Length)
- .ToArray();
-
- internal static Marshaller StreamingHubMarshaller { get; } = new(
+ public static Marshaller StreamingHubMarshaller { get; } = new(
serializer: static (payload, context) =>
{
context.SetPayloadLength(payload.Length);
@@ -32,7 +27,8 @@ internal static class MagicOnionMarshallers
}
);
- internal static Type CreateRequestType(ParameterInfo[] parameters)
+ [RequiresUnreferencedCode(nameof(MagicOnionMarshallers) + "." + nameof(CreateRequestType) + " is incompatible with trimming and Native AOT.")]
+ public static Type CreateRequestType(ParameterInfo[] parameters)
{
if (parameters.Length == 0)
{
@@ -50,18 +46,29 @@ internal static Type CreateRequestType(ParameterInfo[] parameters)
else
{
// start from T2
- var tupleTypeBase = dynamicArgumentTupleTypes[parameters.Length - 2];
+ 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 = dynamicArgumentTupleTypes[arguments.Length - 2];
+ 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/Polyfil/RequiresUnreferencedCodeAttribute.cs b/src/MagicOnion.Internal/Polyfil/RequiresUnreferencedCodeAttribute.cs
new file mode 100644
index 000000000..a59a86c95
--- /dev/null
+++ b/src/MagicOnion.Internal/Polyfil/RequiresUnreferencedCodeAttribute.cs
@@ -0,0 +1,20 @@
+#if !NET6_0_OR_GREATER
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Diagnostics.CodeAnalysis
+{
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
+ internal class RequiresUnreferencedCodeAttribute : Attribute
+ {
+ public string Message { get; }
+ public string? Url { get; }
+
+ public RequiresUnreferencedCodeAttribute(string message)
+ {
+ Message = message;
+ }
+ }
+}
+#endif
diff --git a/src/MagicOnion.Internal/Polyfil/UnconditionalSuppressMessageAttribute.cs b/src/MagicOnion.Internal/Polyfil/UnconditionalSuppressMessageAttribute.cs
new file mode 100644
index 000000000..4e5dff129
--- /dev/null
+++ b/src/MagicOnion.Internal/Polyfil/UnconditionalSuppressMessageAttribute.cs
@@ -0,0 +1,25 @@
+#if !NET6_0_OR_GREATER
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Diagnostics.CodeAnalysis
+{
+ [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 UnconditionalSuppressMessageAttribute(string category, string checkId)
+ {
+ Category = category;
+ CheckId = checkId;
+ }
+ }
+}
+#endif
diff --git a/src/MagicOnion.Internal/Reflection/DynamicAssembly.cs b/src/MagicOnion.Internal/Reflection/DynamicAssembly.cs
index 83972a8c8..6914ec17f 100644
--- a/src/MagicOnion.Internal/Reflection/DynamicAssembly.cs
+++ b/src/MagicOnion.Internal/Reflection/DynamicAssembly.cs
@@ -1,10 +1,12 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
namespace MagicOnion.Internal.Reflection
{
+ [RequiresUnreferencedCode(nameof(DynamicAssembly) + " is incompatible with trimming and Native AOT.")]
#if ENABLE_SAVE_ASSEMBLY
public
#else
diff --git a/src/MagicOnion.Serialization.MessagePack/MagicOnion.Serialization.MessagePack.csproj b/src/MagicOnion.Serialization.MessagePack/MagicOnion.Serialization.MessagePack.csproj
index 1f602aaa5..4ec87bb50 100644
--- a/src/MagicOnion.Serialization.MessagePack/MagicOnion.Serialization.MessagePack.csproj
+++ b/src/MagicOnion.Serialization.MessagePack/MagicOnion.Serialization.MessagePack.csproj
@@ -2,10 +2,11 @@
- netstandard2.0
+ netstandard2.0;netstandard2.1;net8.0
enable
enable
+ true
MagicOnion.Serialization.MessagePack
diff --git a/src/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs b/src/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs
index 76e0e9411..298bb14cc 100644
--- a/src/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs
+++ b/src/MagicOnion.Serialization.MessagePack/MessagePackMagicOnionSerializerProvider.cs
@@ -2,6 +2,7 @@
using System.Buffers;
using System.Linq;
using System.Reflection;
+using System.Runtime.CompilerServices;
using Grpc.Core;
using MessagePack;
using MessagePack.Formatters;
@@ -42,26 +43,43 @@ public MessagePackMagicOnionSerializerProvider WithEnableFallback(bool enableFal
return new MessagePackMagicOnionSerializerProvider(SerializerOptions, enableFallback);
}
+
+#if NET6_0_OR_GREATER
+ [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "ClientFactoryProvider is resolved at runtime.")]
+#endif
public IMagicOnionSerializer Create(MethodType methodType, MethodInfo? methodInfo)
{
var serializerOptions = EnableFallback && methodInfo != null ? WrapFallbackResolverIfNeeded(methodInfo.GetParameters()) : SerializerOptions;
return new MessagePackMagicOnionSerializer(serializerOptions);
}
- static readonly Type[] dynamicArgumentTupleTypes = typeof(DynamicArgumentTuple<,>).GetTypeInfo().Assembly
- .GetTypes()
- .Where(x => x.Name.StartsWith("DynamicArgumentTuple") && !x.Name.Contains("Formatter"))
- .OrderBy(x => x.GetGenericArguments().Length)
- .ToArray();
+#if NET6_0_OR_GREATER
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(nameof(DynamicArgumentTupleTypeCache) + " is incompatible with trimming and Native AOT.")]
+#endif
+ static class DynamicArgumentTupleTypeCache
+ {
+ 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();
+
+ public static readonly Type[] FormatterTypes = typeof(DynamicArgumentTupleFormatter<,,>).GetTypeInfo().Assembly
+ .GetTypes()
+ .Where(x => x.Name.StartsWith("DynamicArgumentTupleFormatter"))
+ .OrderBy(x => x.GetGenericArguments().Length)
+ .ToArray();
+ }
- static readonly Type[] dynamicArgumentTupleFormatterTypes = typeof(DynamicArgumentTupleFormatter<,,>).GetTypeInfo().Assembly
- .GetTypes()
- .Where(x => x.Name.StartsWith("DynamicArgumentTupleFormatter"))
- .OrderBy(x => x.GetGenericArguments().Length)
- .ToArray();
+#if NET6_0_OR_GREATER
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(nameof(DynamicArgumentTupleTypeCache) + " is incompatible with trimming and Native AOT.")]
+#endif
MessagePackSerializerOptions WrapFallbackResolverIfNeeded(ParameterInfo[] parameters)
{
+#if !NETSTANDARD2_0
+ if (!RuntimeFeature.IsDynamicCodeSupported) throw new NotSupportedException("When running with AOT runtime, DynamicArgumentTupleFormatter does not support fallback resolver fro optional parameters.");
+#endif
// If the method has no parameter or one parameter, we don't need to create fallback resolver for optional parameters.
if (parameters.Length < 2)
{
@@ -69,8 +87,8 @@ MessagePackSerializerOptions WrapFallbackResolverIfNeeded(ParameterInfo[] parame
}
// start from T2
- var tupleTypeBase = dynamicArgumentTupleTypes[parameters.Length - 2];
- var formatterTypeBase = dynamicArgumentTupleFormatterTypes[parameters.Length - 2];
+ var tupleTypeBase = DynamicArgumentTupleTypeCache.Types[parameters.Length - 2];
+ var formatterTypeBase = DynamicArgumentTupleTypeCache.FormatterTypes[parameters.Length - 2];
var t = tupleTypeBase.MakeGenericType(parameters.Select(x => x.ParameterType).ToArray());
var formatterType = formatterTypeBase.MakeGenericType(parameters.Select(x => x.ParameterType).ToArray());
diff --git a/tests/MagicOnion.Client.Tests/StreamingHubClientHeartbeatManagerTest.cs b/tests/MagicOnion.Client.Tests/StreamingHubClientHeartbeatManagerTest.cs
index 16f00f3a1..8b705a8d5 100644
--- a/tests/MagicOnion.Client.Tests/StreamingHubClientHeartbeatManagerTest.cs
+++ b/tests/MagicOnion.Client.Tests/StreamingHubClientHeartbeatManagerTest.cs
@@ -281,9 +281,9 @@ public async Task Timeout_IntervalLongerThanTimeout_Keep()
Assert.False(manager.TimeoutToken.IsCancellationRequested);
// Respond to the first message. but it does not respond to subsequent messages.
- manager.ProcessClientHeartbeatResponse(StreamingHubPayloadPool.Shared.RentOrCreate([0x95 /* Array(5) */, 0x7e /* 0x7e(127) */, 0x0 /* Sequence(0) */, .. ToMessagePackBytes(origin.AddSeconds(1)) /* ClientSentAt * /, 0xc0 /* Nil */, 0xc0 /* Nil */]));
- manager.ProcessClientHeartbeatResponse(StreamingHubPayloadPool.Shared.RentOrCreate([0x95 /* Array(5) */, 0x7e /* 0x7e(127) */, 0x1 /* Sequence(1) */, .. ToMessagePackBytes(origin.AddSeconds(2)) /* ClientSentAt * /, 0xc0 /* Nil */, 0xc0 /* Nil */]));
- manager.ProcessClientHeartbeatResponse(StreamingHubPayloadPool.Shared.RentOrCreate([0x95 /* Array(5) */, 0x7e /* 0x7e(127) */, 0x2 /* Sequence(2) */, .. ToMessagePackBytes(origin.AddSeconds(3)) /* ClientSentAt * /, 0xc0 /* Nil */, 0xc0 /* Nil */]));
+ manager.ProcessClientHeartbeatResponse(StreamingHubPayloadPool.Shared.RentOrCreate([0x95 /* Array(5) */, 0x7e /* 0x7e(127) */, 0x0 /* Sequence(0) */, .. ToMessagePackBytes(origin.AddSeconds(1)) /* ClientSentAt */, 0xc0 /* Nil */, 0xc0 /* Nil */]));
+ manager.ProcessClientHeartbeatResponse(StreamingHubPayloadPool.Shared.RentOrCreate([0x95 /* Array(5) */, 0x7e /* 0x7e(127) */, 0x1 /* Sequence(1) */, .. ToMessagePackBytes(origin.AddSeconds(2)) /* ClientSentAt */, 0xc0 /* Nil */, 0xc0 /* Nil */]));
+ manager.ProcessClientHeartbeatResponse(StreamingHubPayloadPool.Shared.RentOrCreate([0x95 /* Array(5) */, 0x7e /* 0x7e(127) */, 0x2 /* Sequence(2) */, .. ToMessagePackBytes(origin.AddSeconds(3)) /* ClientSentAt */, 0xc0 /* Nil */, 0xc0 /* Nil */]));
timeProvider.Advance(TimeSpan.FromMilliseconds(100)); // 3s has elapsed since the first message.
await Task.Delay(10);