diff --git a/src/NServiceBus.Core/DeepCopy.cs b/src/NServiceBus.AcceptanceTesting/Support/DeepCopy.cs
similarity index 98%
rename from src/NServiceBus.Core/DeepCopy.cs
rename to src/NServiceBus.AcceptanceTesting/Support/DeepCopy.cs
index 90c28725d5a..4465722a41e 100644
--- a/src/NServiceBus.Core/DeepCopy.cs
+++ b/src/NServiceBus.AcceptanceTesting/Support/DeepCopy.cs
@@ -1,4 +1,6 @@
-/* This file is copied from https://github.com/Burtsev-Alexey/net-object-deep-copy
+#nullable disable
+
+/* This file is copied from https://github.com/Burtsev-Alexey/net-object-deep-copy
Source code is released under the MIT license.
The MIT License(MIT)
diff --git a/src/NServiceBus.Core/EndpointConfiguration.cs b/src/NServiceBus.Core/EndpointConfiguration.cs
index 2524ab6495a..1061825d9a2 100644
--- a/src/NServiceBus.Core/EndpointConfiguration.cs
+++ b/src/NServiceBus.Core/EndpointConfiguration.cs
@@ -2,13 +2,16 @@ namespace NServiceBus;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Transactions;
using Configuration.AdvancedExtensibility;
using Features;
using Microsoft.Extensions.DependencyInjection;
using Pipeline;
using Settings;
+using Support;
///
/// Configuration used to create an endpoint instance.
@@ -99,10 +102,13 @@ internal void FinalizeConfiguration(IList availableTypes)
{
Settings.SetDefault(conventionsBuilder.Conventions);
- ActivateAndInvoke(availableTypes, t => t.Customize(this));
+ if (RuntimeFeature.IsDynamicCodeSupported)
+ {
+ ActivateAndInvoke(availableTypes, t => t.Customize(this));
#pragma warning disable CS0618 // Type or member is obsolete
- ActivateAndInvoke(availableTypes, t => t.Run(Settings));
+ ActivateAndInvoke(availableTypes, t => t.Run(Settings));
#pragma warning restore CS0618 // Type or member is obsolete
+ }
}
readonly ConventionsBuilder conventionsBuilder;
@@ -120,6 +126,9 @@ static void ValidateEndpointName(string endpointName)
}
}
+#pragma warning disable CS0618 // Type or member is obsolete
+ [RequiresDynamicCode($"Only used for {nameof(INeedInitialization)}) and {nameof(IWantToRunBeforeConfigurationIsFinalized)}")]
+#pragma warning restore CS0618 // Type or member is obsolete
static void ActivateAndInvoke(IList types, Action action) where T : class =>
ForAllTypes(types, t =>
{
diff --git a/src/NServiceBus.Core/Features/ActivatorUtilityBasedFeatureStartupTaskController.cs b/src/NServiceBus.Core/Features/ActivatorUtilityBasedFeatureStartupTaskController.cs
index f72108eebc0..50501ada3fe 100644
--- a/src/NServiceBus.Core/Features/ActivatorUtilityBasedFeatureStartupTaskController.cs
+++ b/src/NServiceBus.Core/Features/ActivatorUtilityBasedFeatureStartupTaskController.cs
@@ -2,8 +2,9 @@
namespace NServiceBus.Features;
+using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;
-sealed class ActivatorUtilityBasedFeatureStartupTaskController() :
+sealed class ActivatorUtilityBasedFeatureStartupTaskController<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TTask>() :
FeatureStartupTaskController(typeof(TTask).Name, static provider => ActivatorUtilities.CreateInstance(provider))
where TTask : FeatureStartupTask;
\ No newline at end of file
diff --git a/src/NServiceBus.Core/Features/Feature.cs b/src/NServiceBus.Core/Features/Feature.cs
index 518a57c12d2..62657282f60 100644
--- a/src/NServiceBus.Core/Features/Feature.cs
+++ b/src/NServiceBus.Core/Features/Feature.cs
@@ -4,6 +4,7 @@ namespace NServiceBus.Features;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Particular.Obsoletes;
using Settings;
@@ -191,7 +192,7 @@ internal static string GetFeatureName() where TFeature : Feature
static IEnabled Enables() where TFeature : Feature, new() => Enabled.Instance;
static IDependency Depends() where TFeature : Feature, new() => Dependency.Instance;
- static IDependency Depends(Type featureType) => !featureType.IsSubclassOf(baseFeatureType) ? throw new ArgumentException($"A Feature can only depend on another Feature. '{featureType.FullName}' is not a Feature", nameof(featureType)) : new TypeDependency(featureType);
+ static IDependency Depends([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllConstructors)] Type featureType) => !featureType.IsSubclassOf(baseFeatureType) ? throw new ArgumentException($"A Feature can only depend on another Feature. '{featureType.FullName}' is not a Feature", nameof(featureType)) : new TypeDependency(featureType);
static IDependency Depends(string featureName) => new WeakDependency(featureName);
readonly List> registeredDefaults = [];
@@ -221,7 +222,7 @@ internal interface IDependency
public static readonly IDependency Instance = new Dependency();
}
- sealed class TypeDependency(Type featureType) : IDependency
+ sealed class TypeDependency([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type featureType) : IDependency
{
public string FeatureName { get; } = GetFeatureName(featureType);
public Feature Create(FeatureFactory factory) => factory.CreateFeature(featureType);
diff --git a/src/NServiceBus.Core/Features/FeatureConfigurationContext.cs b/src/NServiceBus.Core/Features/FeatureConfigurationContext.cs
index 48f1560b244..c9ec17bedd4 100644
--- a/src/NServiceBus.Core/Features/FeatureConfigurationContext.cs
+++ b/src/NServiceBus.Core/Features/FeatureConfigurationContext.cs
@@ -4,6 +4,7 @@ namespace NServiceBus.Features;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;
using Pipeline;
using Settings;
@@ -80,7 +81,7 @@ public void AddSatelliteReceiver(string name, QueueAddress transportAddress, Pus
///
/// The startup task will automatically have all it's constructor parameters resolved from the dependency injection container.
/// The startup task type to register.
- public void RegisterStartupTask() where TTask : FeatureStartupTask
+ public void RegisterStartupTask<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TTask>() where TTask : FeatureStartupTask
=> TaskControllers.Add(new ActivatorUtilityBasedFeatureStartupTaskController());
///
diff --git a/src/NServiceBus.Core/Features/FeatureFactory.cs b/src/NServiceBus.Core/Features/FeatureFactory.cs
index 946619ec71c..0b60dbdc055 100644
--- a/src/NServiceBus.Core/Features/FeatureFactory.cs
+++ b/src/NServiceBus.Core/Features/FeatureFactory.cs
@@ -2,10 +2,11 @@
namespace NServiceBus.Features;
using System;
+using System.Diagnostics.CodeAnalysis;
class FeatureFactory
{
- public virtual Feature CreateFeature(Type featureType) => !typeof(Feature).IsAssignableFrom(featureType)
+ public virtual Feature CreateFeature([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type featureType) => !typeof(Feature).IsAssignableFrom(featureType)
? throw new ArgumentException(
$"The provided type '{featureType.FullName}' is not a valid feature. All features must inherit from '{typeof(Feature).FullName}'.")
: featureType.Construct();
diff --git a/src/NServiceBus.Core/Hosting/StartupDiagnostics/Host.cs b/src/NServiceBus.Core/Hosting/StartupDiagnostics/Host.cs
index bec5e59e01a..11b67b413cc 100644
--- a/src/NServiceBus.Core/Hosting/StartupDiagnostics/Host.cs
+++ b/src/NServiceBus.Core/Hosting/StartupDiagnostics/Host.cs
@@ -2,9 +2,11 @@
namespace NServiceBus;
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using IODirectory = System.IO.Directory;
+[RequiresUnreferencedCode("Attempts to determine application path using Reflection to avoid referencing web assemblies.")]
static class Host
{
public static string GetOutputDirectory()
diff --git a/src/NServiceBus.Core/Installation/InstallerComponent.cs b/src/NServiceBus.Core/Installation/InstallerComponent.cs
index b05daaf5c3a..4c04dfafb34 100644
--- a/src/NServiceBus.Core/Installation/InstallerComponent.cs
+++ b/src/NServiceBus.Core/Installation/InstallerComponent.cs
@@ -4,6 +4,7 @@ namespace NServiceBus;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -44,7 +45,7 @@ public string InstallationUserName
set => settings.Set(UsernameSettingsKey, value);
}
- public void Add() where TInstaller : class, INeedToInstallSomething => installers.Add(new Installer());
+ public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TInstaller>() where TInstaller : class, INeedToInstallSomething => installers.Add(new Installer());
public void AddScannedInstallers(IEnumerable scannedTypes)
{
@@ -62,7 +63,7 @@ public void AddScannedInstallers(IEnumerable scannedTypes)
static bool IsINeedToInstallSomething(Type t) => typeof(INeedToInstallSomething).IsAssignableFrom(t);
- sealed class Installer : IInstaller where T : class, INeedToInstallSomething
+ sealed class Installer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T> : IInstaller where T : class, INeedToInstallSomething
{
public async Task Install(IServiceProvider serviceProvider, string identity, CancellationToken cancellationToken = default)
{
diff --git a/src/NServiceBus.Core/NServiceBus.Core.csproj b/src/NServiceBus.Core/NServiceBus.Core.csproj
index bf58099f57b..ad65a0b3a3a 100644
--- a/src/NServiceBus.Core/NServiceBus.Core.csproj
+++ b/src/NServiceBus.Core/NServiceBus.Core.csproj
@@ -6,6 +6,7 @@
true..\NServiceBus.snktrue
+ true
diff --git a/src/NServiceBus.Core/Pipeline/PipelineExecutionExtensions.cs b/src/NServiceBus.Core/Pipeline/PipelineExecutionExtensions.cs
index 1f6b5a1df74..6aabaeeaeb9 100644
--- a/src/NServiceBus.Core/Pipeline/PipelineExecutionExtensions.cs
+++ b/src/NServiceBus.Core/Pipeline/PipelineExecutionExtensions.cs
@@ -4,6 +4,7 @@ namespace NServiceBus;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
@@ -17,6 +18,7 @@ static class PipelineExecutionExtensions
{
extension(IBehavior[] behaviors)
{
+ [RequiresUnreferencedCode("Requires FastExpressionCompiler")]
public Func CreatePipelineExecutionFuncFor(List? expressions = null)
where TRootContext : IBehaviorContext =>
(Func)behaviors.CreatePipelineExecutionExpression(expressions);
@@ -29,6 +31,7 @@ public Func CreatePipelineExecutionFuncFor(Lis
/// context{N} => GetBehavior(context{N}, {N-1}).Invoke(context{N},
/// context{N+1} => TaskEx.Completed))
///
+ [RequiresUnreferencedCode("Requires FastExpressionCompiler")]
public Delegate CreatePipelineExecutionExpression(List? expressions = null)
{
Delegate? lambdaExpression = null;
@@ -64,6 +67,7 @@ public Delegate CreatePipelineExecutionExpression(List? expressions
///
/// context{i} => GetBehavior(context{i}, {i}).Invoke(context{i+1} => previous)
/// >
+ [RequiresUnreferencedCode("Requires FastExpressionCompiler")]
static Delegate CreateBehaviorCallDelegate(MethodInfo methodInfo, ParameterExpression outerContextParam, Type behaviorType, Delegate previous, int i, List? expressions = null)
{
MethodInfo getBehaviorMethodInfo = GetBehaviorMethodInfo.MakeGenericMethod(outerContextParam.Type, behaviorType);
@@ -84,6 +88,7 @@ public static TBehavior GetBehavior(TContext context, int i
///
/// context{i} => return TaskEx.CompletedTask;
/// >
+ [RequiresUnreferencedCode("Requires FastExpressionCompiler")]
static Delegate CreateDoneDelegate(Type inContextType, int i)
{
var innerContextParam = Expression.Parameter(inContextType, $"context{i + 1}");
diff --git a/src/NServiceBus.Core/Sagas/CustomFinderAdapter.cs b/src/NServiceBus.Core/Sagas/CustomFinderAdapter.cs
index fc8e4ca645d..287e59d9dd4 100644
--- a/src/NServiceBus.Core/Sagas/CustomFinderAdapter.cs
+++ b/src/NServiceBus.Core/Sagas/CustomFinderAdapter.cs
@@ -2,6 +2,7 @@ namespace NServiceBus;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Extensibility;
@@ -9,7 +10,7 @@ namespace NServiceBus;
using Persistence;
using Sagas;
-class CustomFinderAdapter : ICoreSagaFinder where TFinder : ISagaFinder where TSagaData : class, IContainSagaData
+class CustomFinderAdapter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TFinder, TSagaData, TMessage> : ICoreSagaFinder where TFinder : ISagaFinder where TSagaData : class, IContainSagaData
{
public bool IsCustomFinder => true;
diff --git a/src/NServiceBus.Core/Sagas/ExpressionBasedMessagePropertyAccessor.cs b/src/NServiceBus.Core/Sagas/ExpressionBasedMessagePropertyAccessor.cs
index 3850b73ed96..72ebd9c0e91 100644
--- a/src/NServiceBus.Core/Sagas/ExpressionBasedMessagePropertyAccessor.cs
+++ b/src/NServiceBus.Core/Sagas/ExpressionBasedMessagePropertyAccessor.cs
@@ -2,6 +2,7 @@
namespace NServiceBus;
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using FastExpressionCompiler;
using Sagas;
@@ -9,6 +10,7 @@ namespace NServiceBus;
sealed class ExpressionBasedMessagePropertyAccessor(Expression> propertyExpression)
: MessagePropertyAccessor
{
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "CompileFast not used when IsDynamicCodeSupported is true.")]
readonly Func propertyAccessor = System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported ? propertyExpression.CompileFast() :
// Fall back to Expression.Compile or reflection-based getter
propertyExpression.Compile();
diff --git a/src/NServiceBus.Core/Sagas/IConfigureHowToFindSagaWithFinder.cs b/src/NServiceBus.Core/Sagas/IConfigureHowToFindSagaWithFinder.cs
index 8dcf86a7202..d0a5d590b19 100644
--- a/src/NServiceBus.Core/Sagas/IConfigureHowToFindSagaWithFinder.cs
+++ b/src/NServiceBus.Core/Sagas/IConfigureHowToFindSagaWithFinder.cs
@@ -1,6 +1,7 @@
#nullable enable
namespace NServiceBus;
+using System.Diagnostics.CodeAnalysis;
using Sagas;
///
@@ -13,5 +14,5 @@ public interface IConfigureHowToFindSagaWithFinder
///
/// Specify the custom saga finder to match the given message to a saga instance.
///
- void ConfigureMapping() where TFinder : class, ISagaFinder where TSagaEntity : class, IContainSagaData;
+ void ConfigureMapping() where TFinder : class, ISagaFinder where TSagaEntity : class, IContainSagaData;
}
\ No newline at end of file
diff --git a/src/NServiceBus.Core/Sagas/IConfigureSagaNotFoundHandler.cs b/src/NServiceBus.Core/Sagas/IConfigureSagaNotFoundHandler.cs
index 768d34d7de5..12f13a1f146 100644
--- a/src/NServiceBus.Core/Sagas/IConfigureSagaNotFoundHandler.cs
+++ b/src/NServiceBus.Core/Sagas/IConfigureSagaNotFoundHandler.cs
@@ -1,6 +1,8 @@
#nullable enable
namespace NServiceBus;
+using System.Diagnostics.CodeAnalysis;
+
///
/// Implementation provided by the infrastructure - don't implement this
/// unless you intend
@@ -11,5 +13,5 @@ public interface IConfigureSagaNotFoundHandler
///
/// Specifies the optional saga not found handler for this saga instance.
///
- void ConfigureSagaNotFoundHandler() where TNotFoundHandler : ISagaNotFoundHandler;
+ void ConfigureSagaNotFoundHandler<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TNotFoundHandler>() where TNotFoundHandler : ISagaNotFoundHandler;
}
\ No newline at end of file
diff --git a/src/NServiceBus.Core/Sagas/SagaMapper.cs b/src/NServiceBus.Core/Sagas/SagaMapper.cs
index 5f96fee8156..5f6c9c42c8b 100644
--- a/src/NServiceBus.Core/Sagas/SagaMapper.cs
+++ b/src/NServiceBus.Core/Sagas/SagaMapper.cs
@@ -5,6 +5,7 @@ namespace NServiceBus;
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
@@ -55,14 +56,14 @@ void IConfigureHowToFindSagaWithMessageHeaders.ConfigureMapping()
+ void IConfigureHowToFindSagaWithFinder.ConfigureMapping()
{
AssertMessageCanBeMapped($"custom saga finder({typeof(TFinder).FullName})");
finders.Add(new SagaFinderDefinition(new CustomFinderAdapter(), typeof(TMessage)));
}
- void IConfigureSagaNotFoundHandler.ConfigureSagaNotFoundHandler()
+ void IConfigureSagaNotFoundHandler.ConfigureSagaNotFoundHandler<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TNotFoundHandler>()
{
if (notFoundHandler != null)
{
diff --git a/src/NServiceBus.Core/Sagas/SagaNotFoundHandlerInvocation.cs b/src/NServiceBus.Core/Sagas/SagaNotFoundHandlerInvocation.cs
index a9a287d0198..28c28772956 100644
--- a/src/NServiceBus.Core/Sagas/SagaNotFoundHandlerInvocation.cs
+++ b/src/NServiceBus.Core/Sagas/SagaNotFoundHandlerInvocation.cs
@@ -2,10 +2,11 @@
namespace NServiceBus;
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
-sealed class SagaNotFoundHandlerInvocation : ISagaNotFoundHandlerInvocation where TSagaNotFoundHandler : ISagaNotFoundHandler
+sealed class SagaNotFoundHandlerInvocation<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TSagaNotFoundHandler> : ISagaNotFoundHandlerInvocation where TSagaNotFoundHandler : ISagaNotFoundHandler
{
public async Task Invoke(IServiceProvider serviceProvider, object message, IMessageProcessingContext context)
{
diff --git a/src/NServiceBus.Core/Sagas/SagaPropertyMapper.cs b/src/NServiceBus.Core/Sagas/SagaPropertyMapper.cs
index 0745747005d..0c6e8854168 100644
--- a/src/NServiceBus.Core/Sagas/SagaPropertyMapper.cs
+++ b/src/NServiceBus.Core/Sagas/SagaPropertyMapper.cs
@@ -3,6 +3,7 @@
namespace NServiceBus;
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using Sagas;
@@ -20,7 +21,7 @@ internal SagaPropertyMapper(IConfigureHowToFindSagaWithMessage sagaMessageFindin
///
/// The message type to map to.
/// The saga finder that will return the saga.
- public void ConfigureFinderMapping() where TFinder : class, ISagaFinder
+ public void ConfigureFinderMapping() where TFinder : class, ISagaFinder
{
if (sagaMessageFindingConfiguration is not IConfigureHowToFindSagaWithFinder sagaMapperFindingConfiguration)
{
diff --git a/src/NServiceBus.Core/Unicast/MessageHandlerRegistry.cs b/src/NServiceBus.Core/Unicast/MessageHandlerRegistry.cs
index 59856c772f7..4b978cacce6 100644
--- a/src/NServiceBus.Core/Unicast/MessageHandlerRegistry.cs
+++ b/src/NServiceBus.Core/Unicast/MessageHandlerRegistry.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
@@ -62,6 +63,7 @@ from typeHandled in messagesBeingHandled
///
/// Registers the handler type.
///
+ [RequiresUnreferencedCode(WithReflection.TrimWarning)]
public void AddHandler() where THandler : IHandleMessages
{
var handlerType = typeof(THandler);
@@ -82,12 +84,12 @@ public void AddHandler() where THandler : IHandleMessages
var messageType = interfaceType.GetGenericArguments()[0];
if (genericTypeDefinition == typeof(IHandleMessages<>))
{
- _ = AddMessageHandlerForMessageMethod.InvokeGeneric(this, [handlerType, messageType]);
+ _ = WithReflection.AddMessageHandlerForMessageMethod.InvokeGeneric(this, [handlerType, messageType]);
}
if (genericTypeDefinition == typeof(IHandleTimeouts<>))
{
- _ = AddTimeoutHandlerForMessageMethod.InvokeGeneric(this, [handlerType, messageType]);
+ _ = WithReflection.AddTimeoutHandlerForMessageMethod.InvokeGeneric(this, [handlerType, messageType]);
}
}
}
@@ -95,7 +97,7 @@ public void AddHandler() where THandler : IHandleMessages
///
/// Add a handler for a specific message type. Should only be called by a source generator.
///
- public void AddMessageHandlerForMessage() where THandler : class, IHandleMessages
+ public void AddMessageHandlerForMessage<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] THandler, TMessage>() where THandler : class, IHandleMessages
{
// We are keeping a small deduplication set to avoid registering the same handler+message combination multiple times
// and are using a factory to avoid allocation the IMessageHandlerFactory unless it's needed since it can be expensive
@@ -112,7 +114,7 @@ public void AddMessageHandlerForMessage() where THandler : c
///
/// Add a handler for a specific timeout type. Should only be called by a source generator.
///
- public void AddTimeoutHandlerForMessage() where THandler : class, IHandleTimeouts
+ public void AddTimeoutHandlerForMessage<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] THandler, TMessage>() where THandler : class, IHandleTimeouts
{
// We are keeping a small deduplication set to avoid registering the same handler+message combination multiple times
// and are using a factory to avoid allocation the IMessageHandlerFactory unless it's needed since it can be expensive
@@ -140,6 +142,7 @@ List GetOrCreate()
/// Add handlers from types scanned at runtime.
///
/// Scanned types, with "load handlers first" types ordered first.
+ [RequiresUnreferencedCode(WithReflection.TrimWarning)]
public void AddScannedHandlers(IEnumerable orderedTypes)
{
foreach (var type in orderedTypes.Where(IsMessageHandler))
@@ -148,7 +151,7 @@ public void AddScannedHandlers(IEnumerable orderedTypes)
}
}
- internal static bool IsMessageHandler(Type type)
+ internal static bool IsMessageHandler([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] Type type)
{
if (type.IsAbstract || type.IsGenericTypeDefinition)
{
@@ -170,18 +173,25 @@ public void Clear()
deduplicationSet.Clear();
}
+
+ [RequiresUnreferencedCode(WithReflection.TrimWarning)]
void AddHandlerWithReflection(Type handlerType) =>
- AddHandlerWithReflectionMethod.InvokeGeneric(this, [handlerType]);
+ WithReflection.AddHandlerWithReflectionMethod.InvokeGeneric(this, [handlerType]);
- static readonly MethodInfo AddHandlerWithReflectionMethod = typeof(MessageHandlerRegistry)
- .GetMethod(nameof(AddHandler), BindingFlags.Public | BindingFlags.Instance, []) ?? throw new MissingMethodException(nameof(AddHandler));
+ [RequiresUnreferencedCode(TrimWarning)]
+ static class WithReflection
+ {
+ public static readonly MethodInfo AddHandlerWithReflectionMethod = typeof(MessageHandlerRegistry)
+ .GetMethod(nameof(AddHandler), BindingFlags.Public | BindingFlags.Instance, []) ?? throw new MissingMethodException(nameof(AddHandler));
- static readonly MethodInfo AddMessageHandlerForMessageMethod = typeof(MessageHandlerRegistry)
- .GetMethod(nameof(AddMessageHandlerForMessage)) ?? throw new MissingMethodException(nameof(AddMessageHandlerForMessage));
+ public static readonly MethodInfo AddMessageHandlerForMessageMethod = typeof(MessageHandlerRegistry)
+ .GetMethod(nameof(AddMessageHandlerForMessage)) ?? throw new MissingMethodException(nameof(AddMessageHandlerForMessage));
- static readonly MethodInfo AddTimeoutHandlerForMessageMethod = typeof(MessageHandlerRegistry)
- .GetMethod(nameof(AddTimeoutHandlerForMessage)) ?? throw new MissingMethodException(nameof(AddTimeoutHandlerForMessage));
+ public static readonly MethodInfo AddTimeoutHandlerForMessageMethod = typeof(MessageHandlerRegistry)
+ .GetMethod(nameof(AddTimeoutHandlerForMessage)) ?? throw new MissingMethodException(nameof(AddTimeoutHandlerForMessage));
+ public const string TrimWarning = "When adding handlers from assembly scanning using reflection, the methods cannot be trimmed.";
+ }
readonly Dictionary> messageHandlerFactories = [];
readonly HashSet deduplicationSet = [];
@@ -200,7 +210,7 @@ interface IMessageHandlerFactory
MessageHandler Create();
}
- sealed class TimeoutHandlerFactory : IMessageHandlerFactory
+ sealed class TimeoutHandlerFactory<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] THandler, TMessage> : IMessageHandlerFactory
where THandler : class
{
public Type MessageType { get; } = typeof(TMessage);
@@ -220,7 +230,7 @@ public MessageHandler Create() =>
static (sp, args) => Unsafe.As>(factory(sp, args));
}
- sealed class MessageHandlerFactory : IMessageHandlerFactory
+ sealed class MessageHandlerFactory<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] THandler, TMessage> : IMessageHandlerFactory
where THandler : class
{
public Type MessageType { get; } = typeof(TMessage);
diff --git a/src/NServiceBus.Core/Utils/Reflection/DelegateFactory.cs b/src/NServiceBus.Core/Utils/Reflection/DelegateFactory.cs
index 2d088464b7e..c5c3fa56120 100644
--- a/src/NServiceBus.Core/Utils/Reflection/DelegateFactory.cs
+++ b/src/NServiceBus.Core/Utils/Reflection/DelegateFactory.cs
@@ -2,10 +2,13 @@ namespace NServiceBus;
using System;
using System.Collections.Concurrent;
+using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
+[RequiresUnreferencedCode("DelegateFactory is not supported in trimming scenarios. Only used by XmlSerializer.")]
+
static class DelegateFactory
{
public static Func