Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good move especially because the relevant down streams that require deep copy functionality have their own version anyway

https://github.com/search?q=org%3AParticular%20DeepCopy&type=code

Source code is released under the MIT license.
The MIT License(MIT)
Expand Down
13 changes: 11 additions & 2 deletions src/NServiceBus.Core/EndpointConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
/// Configuration used to create an endpoint instance.
Expand Down Expand Up @@ -99,10 +102,13 @@ internal void FinalizeConfiguration(IList<Type> availableTypes)
{
Settings.SetDefault(conventionsBuilder.Conventions);

ActivateAndInvoke<INeedInitialization>(availableTypes, t => t.Customize(this));
if (RuntimeFeature.IsDynamicCodeSupported)
{
ActivateAndInvoke<INeedInitialization>(availableTypes, t => t.Customize(this));
#pragma warning disable CS0618 // Type or member is obsolete
ActivateAndInvoke<IWantToRunBeforeConfigurationIsFinalized>(availableTypes, t => t.Run(Settings));
ActivateAndInvoke<IWantToRunBeforeConfigurationIsFinalized>(availableTypes, t => t.Run(Settings));
#pragma warning restore CS0618 // Type or member is obsolete
}
}

readonly ConventionsBuilder conventionsBuilder;
Expand All @@ -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<T>(IList<Type> types, Action<T> action) where T : class =>
ForAllTypes<T>(types, t =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

namespace NServiceBus.Features;

using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;

sealed class ActivatorUtilityBasedFeatureStartupTaskController<TTask>() :
sealed class ActivatorUtilityBasedFeatureStartupTaskController<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TTask>() :
FeatureStartupTaskController(typeof(TTask).Name, static provider => ActivatorUtilities.CreateInstance<TTask>(provider))
where TTask : FeatureStartupTask;
5 changes: 3 additions & 2 deletions src/NServiceBus.Core/Features/Feature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Particular.Obsoletes;
using Settings;
Expand Down Expand Up @@ -117,7 +118,7 @@
{
ArgumentNullException.ThrowIfNull(features);

dependencies.Add([.. features.Select(Depends)]);

Check failure on line 121 in src/NServiceBus.Core/Features/Feature.cs

View workflow job for this annotation

GitHub Actions / Linux

Method 'NServiceBus.Features.Feature.Depends(Type)' with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method.

Check failure on line 121 in src/NServiceBus.Core/Features/Feature.cs

View workflow job for this annotation

GitHub Actions / Windows

Method 'NServiceBus.Features.Feature.Depends(Type)' with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method.
}

/// <summary>
Expand Down Expand Up @@ -191,7 +192,7 @@

static IEnabled Enables<TFeature>() where TFeature : Feature, new() => Enabled<TFeature>.Instance;
static IDependency Depends<TFeature>() where TFeature : Feature, new() => Dependency<TFeature>.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<Action<SettingsHolder>> registeredDefaults = [];
Expand Down Expand Up @@ -221,7 +222,7 @@
public static readonly IDependency Instance = new Dependency<TFeature>();
}

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);
Expand Down
3 changes: 2 additions & 1 deletion src/NServiceBus.Core/Features/FeatureConfigurationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -80,7 +81,7 @@ public void AddSatelliteReceiver(string name, QueueAddress transportAddress, Pus
/// </summary>
/// <remarks>The startup task will automatically have all it's constructor parameters resolved from the dependency injection container.</remarks>
/// <typeparam name="TTask">The startup task type to register.</typeparam>
public void RegisterStartupTask<TTask>() where TTask : FeatureStartupTask
public void RegisterStartupTask<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TTask>() where TTask : FeatureStartupTask
=> TaskControllers.Add(new ActivatorUtilityBasedFeatureStartupTaskController<TTask>());

/// <summary>
Expand Down
3 changes: 2 additions & 1 deletion src/NServiceBus.Core/Features/FeatureFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Feature>();
Expand Down
2 changes: 2 additions & 0 deletions src/NServiceBus.Core/Hosting/StartupDiagnostics/Host.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
5 changes: 3 additions & 2 deletions src/NServiceBus.Core/Installation/InstallerComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -44,7 +45,7 @@ public string InstallationUserName
set => settings.Set(UsernameSettingsKey, value);
}

public void Add<TInstaller>() where TInstaller : class, INeedToInstallSomething => installers.Add(new Installer<TInstaller>());
public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TInstaller>() where TInstaller : class, INeedToInstallSomething => installers.Add(new Installer<TInstaller>());

public void AddScannedInstallers(IEnumerable<Type> scannedTypes)
{
Expand All @@ -62,7 +63,7 @@ public void AddScannedInstallers(IEnumerable<Type> scannedTypes)

static bool IsINeedToInstallSomething(Type t) => typeof(INeedToInstallSomething).IsAssignableFrom(t);

sealed class Installer<T> : 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)
{
Expand Down
1 change: 1 addition & 0 deletions src/NServiceBus.Core/NServiceBus.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\NServiceBus.snk</AssemblyOriginatorKeyFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>

<ItemGroup>
Expand Down
5 changes: 5 additions & 0 deletions src/NServiceBus.Core/Pipeline/PipelineExecutionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -17,6 +18,7 @@ static class PipelineExecutionExtensions
{
extension(IBehavior[] behaviors)
{
[RequiresUnreferencedCode("Requires FastExpressionCompiler")]
public Func<TRootContext, Task> CreatePipelineExecutionFuncFor<TRootContext>(List<Expression>? expressions = null)
where TRootContext : IBehaviorContext =>
(Func<TRootContext, Task>)behaviors.CreatePipelineExecutionExpression(expressions);
Expand All @@ -29,6 +31,7 @@ public Func<TRootContext, Task> CreatePipelineExecutionFuncFor<TRootContext>(Lis
/// context{N} => GetBehavior(context{N}, {N-1}).Invoke(context{N},
/// context{N+1} => TaskEx.Completed))
/// </code>
[RequiresUnreferencedCode("Requires FastExpressionCompiler")]
public Delegate CreatePipelineExecutionExpression(List<Expression>? expressions = null)
{
Delegate? lambdaExpression = null;
Expand Down Expand Up @@ -64,6 +67,7 @@ public Delegate CreatePipelineExecutionExpression(List<Expression>? expressions
/// <code>
/// context{i} => GetBehavior(context{i}, {i}).Invoke(context{i+1} => previous)
/// </code>>
[RequiresUnreferencedCode("Requires FastExpressionCompiler")]
static Delegate CreateBehaviorCallDelegate(MethodInfo methodInfo, ParameterExpression outerContextParam, Type behaviorType, Delegate previous, int i, List<Expression>? expressions = null)
{
MethodInfo getBehaviorMethodInfo = GetBehaviorMethodInfo.MakeGenericMethod(outerContextParam.Type, behaviorType);
Expand All @@ -84,6 +88,7 @@ public static TBehavior GetBehavior<TContext, TBehavior>(TContext context, int i
/// <code>
/// context{i} => return TaskEx.CompletedTask;
/// </code>>
[RequiresUnreferencedCode("Requires FastExpressionCompiler")]
static Delegate CreateDoneDelegate(Type inContextType, int i)
{
var innerContextParam = Expression.Parameter(inContextType, $"context{i + 1}");
Expand Down
3 changes: 2 additions & 1 deletion src/NServiceBus.Core/Sagas/CustomFinderAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ namespace NServiceBus;

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Extensibility;
using Microsoft.Extensions.DependencyInjection;
using Persistence;
using Sagas;

class CustomFinderAdapter<TFinder, TSagaData, TMessage> : ICoreSagaFinder where TFinder : ISagaFinder<TSagaData, TMessage> where TSagaData : class, IContainSagaData
class CustomFinderAdapter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TFinder, TSagaData, TMessage> : ICoreSagaFinder where TFinder : ISagaFinder<TSagaData, TMessage> where TSagaData : class, IContainSagaData
{
public bool IsCustomFinder => true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
namespace NServiceBus;

using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using FastExpressionCompiler;
using Sagas;

sealed class ExpressionBasedMessagePropertyAccessor<TMessage>(Expression<Func<TMessage, object?>> propertyExpression)
: MessagePropertyAccessor<TMessage>
{
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "CompileFast not used when IsDynamicCodeSupported is true.")]
readonly Func<TMessage, object?> propertyAccessor = System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported ? propertyExpression.CompileFast() :
// Fall back to Expression.Compile or reflection-based getter
propertyExpression.Compile();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#nullable enable
namespace NServiceBus;

using System.Diagnostics.CodeAnalysis;
using Sagas;

/// <summary>
Expand All @@ -13,5 +14,5 @@ public interface IConfigureHowToFindSagaWithFinder
/// <summary>
/// Specify the custom saga finder to match the given message to a saga instance.
/// </summary>
void ConfigureMapping<TSagaEntity, TMessage, TFinder>() where TFinder : class, ISagaFinder<TSagaEntity, TMessage> where TSagaEntity : class, IContainSagaData;
void ConfigureMapping<TSagaEntity, TMessage, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TFinder>() where TFinder : class, ISagaFinder<TSagaEntity, TMessage> where TSagaEntity : class, IContainSagaData;
}
4 changes: 3 additions & 1 deletion src/NServiceBus.Core/Sagas/IConfigureSagaNotFoundHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#nullable enable
namespace NServiceBus;

using System.Diagnostics.CodeAnalysis;

/// <summary>
/// Implementation provided by the infrastructure - don't implement this
/// unless you intend
Expand All @@ -11,5 +13,5 @@ public interface IConfigureSagaNotFoundHandler
/// <summary>
/// Specifies the optional saga not found handler for this saga instance.
/// </summary>
void ConfigureSagaNotFoundHandler<TNotFoundHandler>() where TNotFoundHandler : ISagaNotFoundHandler;
void ConfigureSagaNotFoundHandler<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TNotFoundHandler>() where TNotFoundHandler : ISagaNotFoundHandler;
}
5 changes: 3 additions & 2 deletions src/NServiceBus.Core/Sagas/SagaMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -55,14 +56,14 @@ void IConfigureHowToFindSagaWithMessageHeaders.ConfigureMapping<TSagaEntity, TMe
typeof(TMessage)));
}

void IConfigureHowToFindSagaWithFinder.ConfigureMapping<TSagaEntity, TMessage, TFinder>()
void IConfigureHowToFindSagaWithFinder.ConfigureMapping<TSagaEntity, TMessage, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TFinder>()
{
AssertMessageCanBeMapped<TMessage>($"custom saga finder({typeof(TFinder).FullName})");

finders.Add(new SagaFinderDefinition(new CustomFinderAdapter<TFinder, TSagaEntity, TMessage>(), typeof(TMessage)));
}

void IConfigureSagaNotFoundHandler.ConfigureSagaNotFoundHandler<TNotFoundHandler>()
void IConfigureSagaNotFoundHandler.ConfigureSagaNotFoundHandler<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TNotFoundHandler>()
{
if (notFoundHandler != null)
{
Expand Down
3 changes: 2 additions & 1 deletion src/NServiceBus.Core/Sagas/SagaNotFoundHandlerInvocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
namespace NServiceBus;

using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

sealed class SagaNotFoundHandlerInvocation<TSagaNotFoundHandler> : 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)
{
Expand Down
3 changes: 2 additions & 1 deletion src/NServiceBus.Core/Sagas/SagaPropertyMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace NServiceBus;

using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using Sagas;

Expand All @@ -20,7 +21,7 @@ internal SagaPropertyMapper(IConfigureHowToFindSagaWithMessage sagaMessageFindin
/// </summary>
/// <typeparam name="TMessage">The message type to map to.</typeparam>
/// <typeparam name="TFinder">The saga finder that will return the saga.</typeparam>
public void ConfigureFinderMapping<TMessage, TFinder>() where TFinder : class, ISagaFinder<TSagaData, TMessage>
public void ConfigureFinderMapping<TMessage, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TFinder>() where TFinder : class, ISagaFinder<TSagaData, TMessage>
{
if (sagaMessageFindingConfiguration is not IConfigureHowToFindSagaWithFinder sagaMapperFindingConfiguration)
{
Expand Down
Loading
Loading