diff --git a/src/LegacySupport/DynamicDependencyAttribute.cs b/src/LegacySupport/DynamicDependencyAttribute.cs
new file mode 100644
index 00000000000..e021a12de96
--- /dev/null
+++ b/src/LegacySupport/DynamicDependencyAttribute.cs
@@ -0,0 +1,136 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#pragma warning disable IDE0079
+#pragma warning disable SA1101
+#pragma warning disable SA1116
+#pragma warning disable SA1117
+#pragma warning disable SA1512
+#pragma warning disable SA1623
+#pragma warning disable SA1642
+#pragma warning disable S3903
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// States a dependency that one member has on another.
+///
+///
+/// This can be used to inform tooling of a dependency that is otherwise not evident purely from
+/// metadata and IL, for example a member relied on via reflection.
+///
+[AttributeUsage(
+ AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method,
+ AllowMultiple = true, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class DynamicDependencyAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified signature of a member on the same type as the consumer.
+ ///
+ /// The signature of the member depended on.
+ public DynamicDependencyAttribute(string memberSignature) => MemberSignature = memberSignature;
+
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified signature of a member on a .
+ ///
+ /// The signature of the member depended on.
+ /// The containing .
+ public DynamicDependencyAttribute(string memberSignature, Type type)
+ {
+ MemberSignature = memberSignature;
+ Type = type;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified signature of a member on a type in an assembly.
+ ///
+ /// The signature of the member depended on.
+ /// The full name of the type containing the specified member.
+ /// The assembly name of the type containing the specified member.
+ public DynamicDependencyAttribute(string memberSignature, string typeName, string assemblyName)
+ {
+ MemberSignature = memberSignature;
+ TypeName = typeName;
+ AssemblyName = assemblyName;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified types of members on a .
+ ///
+ /// The types of members depended on.
+ /// The containing the specified members.
+ public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, Type type)
+ {
+ MemberTypes = memberTypes;
+ Type = type;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified types of members on a type in an assembly.
+ ///
+ /// The types of members depended on.
+ /// The full name of the type containing the specified members.
+ /// The assembly name of the type containing the specified members.
+ public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName)
+ {
+ MemberTypes = memberTypes;
+ TypeName = typeName;
+ AssemblyName = assemblyName;
+ }
+
+ ///
+ /// Gets the signature of the member depended on.
+ ///
+ ///
+ /// Either must be a valid string or
+ /// must not equal , but not both.
+ ///
+ public string? MemberSignature { get; }
+
+ ///
+ /// Gets the which specifies the type
+ /// of members depended on.
+ ///
+ ///
+ /// Either must be a valid string or
+ /// must not equal , but not both.
+ ///
+ public DynamicallyAccessedMemberTypes MemberTypes { get; }
+
+ ///
+ /// Gets the containing the specified member.
+ ///
+ ///
+ /// If neither nor are specified,
+ /// the type of the consumer is assumed.
+ ///
+ public Type? Type { get; }
+
+ ///
+ /// Gets the full name of the type containing the specified member.
+ ///
+ ///
+ /// If neither nor are specified,
+ /// the type of the consumer is assumed.
+ ///
+ public string? TypeName { get; }
+
+ ///
+ /// Gets the assembly name of the specified type.
+ ///
+ ///
+ /// is only valid when is specified.
+ ///
+ public string? AssemblyName { get; }
+
+ ///
+ /// Gets or sets the condition in which the dependency is applicable, e.g. "DEBUG".
+ ///
+ public string? Condition { get; set; }
+}
diff --git a/src/LegacySupport/DynamicallyAccessedMemberTypes.cs b/src/LegacySupport/DynamicallyAccessedMemberTypes.cs
new file mode 100644
index 00000000000..eb6326d5a3c
--- /dev/null
+++ b/src/LegacySupport/DynamicallyAccessedMemberTypes.cs
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#pragma warning disable IDE0079
+#pragma warning disable CA2217
+#pragma warning disable SA1413
+#pragma warning disable SA1512
+#pragma warning disable S4070
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// Specifies the types of members that are dynamically accessed.
+///
+/// This enumeration has a attribute that allows a
+/// bitwise combination of its member values.
+///
+[Flags]
+internal enum DynamicallyAccessedMemberTypes
+{
+ ///
+ /// Specifies no members.
+ ///
+ None = 0,
+
+ ///
+ /// Specifies the default, parameterless public constructor.
+ ///
+ PublicParameterlessConstructor = 0x0001,
+
+ ///
+ /// Specifies all public constructors.
+ ///
+ PublicConstructors = 0x0002 | PublicParameterlessConstructor,
+
+ ///
+ /// Specifies all non-public constructors.
+ ///
+ NonPublicConstructors = 0x0004,
+
+ ///
+ /// Specifies all public methods.
+ ///
+ PublicMethods = 0x0008,
+
+ ///
+ /// Specifies all non-public methods.
+ ///
+ NonPublicMethods = 0x0010,
+
+ ///
+ /// Specifies all public fields.
+ ///
+ PublicFields = 0x0020,
+
+ ///
+ /// Specifies all non-public fields.
+ ///
+ NonPublicFields = 0x0040,
+
+ ///
+ /// Specifies all public nested types.
+ ///
+ PublicNestedTypes = 0x0080,
+
+ ///
+ /// Specifies all non-public nested types.
+ ///
+ NonPublicNestedTypes = 0x0100,
+
+ ///
+ /// Specifies all public properties.
+ ///
+ PublicProperties = 0x0200,
+
+ ///
+ /// Specifies all non-public properties.
+ ///
+ NonPublicProperties = 0x0400,
+
+ ///
+ /// Specifies all public events.
+ ///
+ PublicEvents = 0x0800,
+
+ ///
+ /// Specifies all non-public events.
+ ///
+ NonPublicEvents = 0x1000,
+
+ ///
+ /// Specifies all interfaces implemented by the type.
+ ///
+ Interfaces = 0x2000,
+
+ ///
+ /// Specifies all members.
+ ///
+ All = ~None
+}
diff --git a/src/LegacySupport/DynamicallyAccessedMembersAttribute.cs b/src/LegacySupport/DynamicallyAccessedMembersAttribute.cs
new file mode 100644
index 00000000000..10a900a9601
--- /dev/null
+++ b/src/LegacySupport/DynamicallyAccessedMembersAttribute.cs
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#pragma warning disable IDE0079
+#pragma warning disable SA1101
+#pragma warning disable SA1116
+#pragma warning disable SA1117
+#pragma warning disable SA1512
+#pragma warning disable SA1623
+#pragma warning disable SA1642
+#pragma warning disable S3903
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// Indicates that certain members on a specified are accessed dynamically,
+/// for example through .
+///
+///
+/// This allows tools to understand which members are being accessed during the execution
+/// of a program.
+///
+/// This attribute is valid on members whose type is or .
+///
+/// When this attribute is applied to a location of type , the assumption is
+/// that the string represents a fully qualified type name.
+///
+/// When this attribute is applied to a class, interface, or struct, the members specified
+/// can be accessed dynamically on instances returned from calling
+/// on instances of that class, interface, or struct.
+///
+/// If the attribute is applied to a method it's treated as a special case and it implies
+/// the attribute should be applied to the "this" parameter of the method. As such the attribute
+/// should only be used on instance methods of types assignable to System.Type (or string, but no methods
+/// will use it there).
+///
+[AttributeUsage(
+ AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
+ AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method |
+ AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct,
+ Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class DynamicallyAccessedMembersAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified member types.
+ ///
+ /// The types of members dynamically accessed.
+ public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) => MemberTypes = memberTypes;
+
+ ///
+ /// Gets the which specifies the type
+ /// of members dynamically accessed.
+ ///
+ public DynamicallyAccessedMemberTypes MemberTypes { get; }
+}
diff --git a/src/LegacySupport/RequiresUnreferencedCodeAttribute.cs b/src/LegacySupport/RequiresUnreferencedCodeAttribute.cs
new file mode 100644
index 00000000000..876d514812b
--- /dev/null
+++ b/src/LegacySupport/RequiresUnreferencedCodeAttribute.cs
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#pragma warning disable IDE0079
+#pragma warning disable SA1101
+#pragma warning disable SA1116
+#pragma warning disable SA1117
+#pragma warning disable SA1512
+#pragma warning disable SA1623
+#pragma warning disable SA1642
+#pragma warning disable S3903
+#pragma warning disable S3996
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// /// Indicates that the specified method requires dynamic access to code that is not referenced
+/// statically, for example through .
+///
+///
+/// This allows tools to understand which methods are unsafe to call when removing unreferenced
+/// code from an application.
+///
+[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
+[ExcludeFromCodeCoverage]
+internal sealed class RequiresUnreferencedCodeAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified message.
+ ///
+ ///
+ /// A message that contains information about the usage of unreferenced code.
+ ///
+ public RequiresUnreferencedCodeAttribute(string message) => Message = message;
+
+ ///
+ /// Gets a message that contains information about the usage of unreferenced code.
+ ///
+ public string Message { get; }
+
+ ///
+ /// Gets or sets an optional URL that contains more information about the method,
+ /// why it requires unreferenced code, and what options a consumer has to deal with it.
+ ///
+ public string? Url { get; set; }
+}
diff --git a/src/LegacySupport/UnconditionalSuppressMessageAttribute.cs b/src/LegacySupport/UnconditionalSuppressMessageAttribute.cs
new file mode 100644
index 00000000000..50a66797c10
--- /dev/null
+++ b/src/LegacySupport/UnconditionalSuppressMessageAttribute.cs
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#pragma warning disable IDE0079
+#pragma warning disable SA1101
+#pragma warning disable SA1116
+#pragma warning disable SA1117
+#pragma warning disable SA1512
+#pragma warning disable SA1623
+#pragma warning disable SA1642
+#pragma warning disable S3903
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// /// Suppresses reporting of a specific rule violation, allowing multiple suppressions on a
+/// single code artifact.
+///
+///
+/// is different than
+/// in that it doesn't have a
+/// . So it is always preserved in the compiled assembly.
+///
+[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
+[ExcludeFromCodeCoverage]
+internal sealed class UnconditionalSuppressMessageAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the
+ /// class, specifying the category of the tool and the identifier for an analysis rule.
+ ///
+ /// The category for the attribute.
+ /// The identifier of the analysis rule the attribute applies to.
+ public UnconditionalSuppressMessageAttribute(string category, string checkId)
+ {
+ Category = category;
+ CheckId = checkId;
+ }
+
+ ///
+ /// Gets the category identifying the classification of the attribute.
+ ///
+ ///
+ /// The property describes the tool or tool analysis category
+ /// for which a message suppression attribute applies.
+ ///
+ public string Category { get; }
+
+ ///
+ /// Gets the identifier of the analysis tool rule to be suppressed.
+ ///
+ ///
+ /// Concatenated together, the and
+ /// properties form a unique check identifier.
+ ///
+ public string CheckId { get; }
+
+ ///
+ /// Gets or sets the scope of the code that is relevant for the attribute.
+ ///
+ ///
+ /// The Scope property is an optional argument that specifies the metadata scope for which
+ /// the attribute is relevant.
+ ///
+ public string? Scope { get; set; }
+
+ ///
+ /// Gets or sets a fully qualified path that represents the target of the attribute.
+ ///
+ ///
+ /// The property is an optional argument identifying the analysis target
+ /// of the attribute. An example value is "System.IO.Stream.ctor():System.Void".
+ /// Because it is fully qualified, it can be long, particularly for targets such as parameters.
+ /// The analysis tool user interface should be capable of automatically formatting the parameter.
+ ///
+ public string? Target { get; set; }
+
+ ///
+ /// Gets or sets an optional argument expanding on exclusion criteria.
+ ///
+ ///
+ /// The property is an optional argument that specifies additional
+ /// exclusion where the literal metadata target is not sufficiently precise. For example,
+ /// the cannot be applied within a method,
+ /// and it may be desirable to suppress a violation against a statement in the method that will
+ /// give a rule violation, but not against all statements in the method.
+ ///
+ public string? MessageId { get; set; }
+
+ ///
+ /// Gets or sets the justification for suppressing the code analysis message.
+ ///
+ public string? Justification { get; set; }
+}
diff --git a/src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.TResult.cs b/src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.TResult.cs
index 93ecd2b0c13..b2fccbcf247 100644
--- a/src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.TResult.cs
+++ b/src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.TResult.cs
@@ -42,6 +42,7 @@ public class AdvancedCircuitBreakerStrategyOptions : CircuitBreakerStra
[Range(CircuitBreakerConstants.MinimumValidThroughput, int.MaxValue)]
public int MinimumThroughput { get; set; } = CircuitBreakerConstants.DefaultMinimumThroughput;
+#pragma warning disable IL2026 // Addressed with DynamicDependency on ValidationHelper.Validate method
///
/// Gets or sets the duration of the sampling over which failure ratios are assessed.
///
@@ -50,4 +51,5 @@ public class AdvancedCircuitBreakerStrategyOptions : CircuitBreakerStra
///
[Range(typeof(TimeSpan), "00:00:00.500", "1.00:00:00")]
public TimeSpan SamplingDuration { get; set; } = CircuitBreakerConstants.DefaultSamplingDuration;
+#pragma warning restore IL2026
}
diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderExtensions.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderExtensions.cs
index 67d0388888f..fdb3ee02d74 100644
--- a/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderExtensions.cs
+++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderExtensions.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Diagnostics.CodeAnalysis;
using Polly.CircuitBreaker;
using Polly.CircuitBreaker.Health;
@@ -99,6 +100,10 @@ public static ResilienceStrategyBuilder AddSimpleCircuitBreaker(this ResilienceS
return builder.AddSimpleCircuitBreakerCore(options);
}
+ [UnconditionalSuppressMessage(
+ "Trimming",
+ "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
+ Justification = "All options members preserved.")]
private static TBuilder AddAdvancedCircuitBreakerCore(this TBuilder builder, AdvancedCircuitBreakerStrategyOptions options)
where TBuilder : ResilienceStrategyBuilderBase
{
@@ -110,18 +115,30 @@ private static TBuilder AddAdvancedCircuitBreakerCore(this TB
options.MinimumThroughput,
HealthMetrics.Create(options.SamplingDuration, context.TimeProvider));
- return CreateStrategy(context, options, behavior);
+ return CreateStrategy>(context, options, behavior);
},
options);
}
+ [UnconditionalSuppressMessage(
+ "Trimming",
+ "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
+ Justification = "All options members preserved.")]
private static TBuilder AddSimpleCircuitBreakerCore(this TBuilder builder, SimpleCircuitBreakerStrategyOptions options)
where TBuilder : ResilienceStrategyBuilderBase
{
- return builder.AddStrategy(context => CreateStrategy(context, options, new ConsecutiveFailuresCircuitBehavior(options.FailureThreshold)), options);
+ return builder.AddStrategy(
+ context =>
+ {
+ return CreateStrategy>(
+ context,
+ options,
+ new ConsecutiveFailuresCircuitBehavior(options.FailureThreshold));
+ },
+ options);
}
- internal static CircuitBreakerResilienceStrategy CreateStrategy(
+ internal static CircuitBreakerResilienceStrategy CreateStrategy(
ResilienceStrategyBuilderContext context,
CircuitBreakerStrategyOptions options,
CircuitBehavior behavior)
diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.cs
index 5fb5fbc1243..da30948b6a2 100644
--- a/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.cs
+++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.cs
@@ -23,6 +23,7 @@ public abstract class CircuitBreakerStrategyOptions : ResilienceStrateg
/// Returns CircuitBreaker value.
public sealed override string StrategyType => CircuitBreakerConstants.StrategyType;
+#pragma warning disable IL2026 // Addressed with DynamicDependency on ValidationHelper.Validate method
///
/// Gets or sets the duration of break the circuit will stay open before resetting.
///
@@ -31,6 +32,7 @@ public abstract class CircuitBreakerStrategyOptions : ResilienceStrateg
///
[Range(typeof(TimeSpan), "00:00:00.500", "1.00:00:00")]
public TimeSpan BreakDuration { get; set; } = CircuitBreakerConstants.DefaultBreakDuration;
+#pragma warning restore
///
/// Gets or sets the predicates for the circuit breaker.
diff --git a/src/Polly.Core/Fallback/FallbackResilienceStrategyBuilderExtensions.cs b/src/Polly.Core/Fallback/FallbackResilienceStrategyBuilderExtensions.cs
index 89ee15dbddc..b361f5b5014 100644
--- a/src/Polly.Core/Fallback/FallbackResilienceStrategyBuilderExtensions.cs
+++ b/src/Polly.Core/Fallback/FallbackResilienceStrategyBuilderExtensions.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Diagnostics.CodeAnalysis;
using Polly.Fallback;
namespace Polly;
@@ -22,7 +23,7 @@ public static ResilienceStrategyBuilder AddFallback(this Resil
Guard.NotNull(builder);
Guard.NotNull(options);
- builder.AddFallbackCore(options);
+ builder.AddFallbackCore>(options);
return builder;
}
@@ -39,11 +40,17 @@ internal static ResilienceStrategyBuilder AddFallback(this ResilienceStrategyBui
Guard.NotNull(builder);
Guard.NotNull(options);
- builder.AddFallbackCore(options);
+ builder.AddFallbackCore