diff --git a/src/Microsoft.FeatureManagement/FeatureFilterEvaluationContext.cs b/src/Microsoft.FeatureManagement/FeatureFilterEvaluationContext.cs
index 2591e667..91589852 100644
--- a/src/Microsoft.FeatureManagement/FeatureFilterEvaluationContext.cs
+++ b/src/Microsoft.FeatureManagement/FeatureFilterEvaluationContext.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license.
//
using Microsoft.Extensions.Configuration;
+using System.Threading;
namespace Microsoft.FeatureManagement
{
@@ -25,5 +26,10 @@ public class FeatureFilterEvaluationContext
/// The settings are made available for s that implement .
///
public object Settings { get; set; }
+
+ ///
+ /// A cancellation token that can be used to request cancellation of the feature evaluation operation.
+ ///
+ public CancellationToken CancellationToken { get; set; }
}
}
diff --git a/src/Microsoft.FeatureManagement/FeatureManager.cs b/src/Microsoft.FeatureManagement/FeatureManager.cs
index a066078f..2be9361f 100644
--- a/src/Microsoft.FeatureManagement/FeatureManager.cs
+++ b/src/Microsoft.FeatureManagement/FeatureManager.cs
@@ -473,6 +473,8 @@ private async ValueTask IsEnabledAsync(FeatureDefinition feature
// For all enabling filters listed in the feature's state, evaluate them according to requirement type
foreach (FeatureFilterConfiguration featureFilterConfiguration in featureDefinition.EnabledFor)
{
+ cancellationToken.ThrowIfCancellationRequested();
+
filterIndex++;
//
@@ -525,7 +527,8 @@ private async ValueTask IsEnabledAsync(FeatureDefinition feature
var context = new FeatureFilterEvaluationContext()
{
FeatureName = featureDefinition.Name,
- Parameters = featureFilterConfiguration.Parameters
+ Parameters = featureFilterConfiguration.Parameters,
+ CancellationToken = cancellationToken
};
BindSettings(filter, context, filterIndex);
@@ -612,6 +615,8 @@ private ValueTask AssignVariantAsync(EvaluationEvent evaluati
{
foreach (UserAllocation user in evaluationEvent.FeatureDefinition.Allocation.User)
{
+ cancellationToken.ThrowIfCancellationRequested();
+
if (TargetingEvaluator.IsTargeted(targetingContext.UserId, user.Users, _assignerOptions.IgnoreCase))
{
if (string.IsNullOrEmpty(user.Variant))
@@ -638,6 +643,8 @@ private ValueTask AssignVariantAsync(EvaluationEvent evaluati
{
foreach (GroupAllocation group in evaluationEvent.FeatureDefinition.Allocation.Group)
{
+ cancellationToken.ThrowIfCancellationRequested();
+
if (TargetingEvaluator.IsTargeted(targetingContext.Groups, group.Groups, _assignerOptions.IgnoreCase))
{
if (string.IsNullOrEmpty(group.Variant))
@@ -664,6 +671,8 @@ private ValueTask AssignVariantAsync(EvaluationEvent evaluati
{
foreach (PercentileAllocation percentile in evaluationEvent.FeatureDefinition.Allocation.Percentile)
{
+ cancellationToken.ThrowIfCancellationRequested();
+
if (TargetingEvaluator.IsTargeted(
targetingContext,
percentile.From,
@@ -796,7 +805,7 @@ private bool IsMatchingName(Type filterType, string filterName)
//
// Feature filters can have namespaces in their alias
// If a feature is configured to use a filter without a namespace such as 'MyFilter', then it can match 'MyOrg.MyProduct.MyFilter' or simply 'MyFilter'
- // If a feature is configured to use a filter with a namespace such as 'MyOrg.MyProduct.MyFilter' then it can only match 'MyOrg.MyProduct.MyFilter'
+ // If a feature is configured to use a filter with a namespace such as 'MyOrg.MyProduct.MyFilter' then it can only match 'MyOrg.MyProduct.MyFilter'
if (filterName.Contains('.'))
{
//