Skip to content
Merged
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
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license.
//
using Microsoft.Extensions.Configuration;
using System.Threading;

namespace Microsoft.FeatureManagement
{
Expand All @@ -25,5 +26,10 @@ public class FeatureFilterEvaluationContext
/// The settings are made available for <see cref="IFeatureFilter"/>s that implement <see cref="IFilterParametersBinder"/>.
/// </summary>
public object Settings { get; set; }

/// <summary>
/// A cancellation token that can be used to request cancellation of the feature evaluation operation.
/// </summary>
public CancellationToken CancellationToken { get; set; }
}
}
13 changes: 11 additions & 2 deletions src/Microsoft.FeatureManagement/FeatureManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,8 @@ private async ValueTask<bool> IsEnabledAsync<TContext>(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++;

//
Expand Down Expand Up @@ -525,7 +527,8 @@ private async ValueTask<bool> IsEnabledAsync<TContext>(FeatureDefinition feature
var context = new FeatureFilterEvaluationContext()
{
FeatureName = featureDefinition.Name,
Parameters = featureFilterConfiguration.Parameters
Parameters = featureFilterConfiguration.Parameters,
CancellationToken = cancellationToken
};

BindSettings(filter, context, filterIndex);
Expand Down Expand Up @@ -612,6 +615,8 @@ private ValueTask<VariantDefinition> 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))
Expand All @@ -638,6 +643,8 @@ private ValueTask<VariantDefinition> 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))
Expand All @@ -664,6 +671,8 @@ private ValueTask<VariantDefinition> AssignVariantAsync(EvaluationEvent evaluati
{
foreach (PercentileAllocation percentile in evaluationEvent.FeatureDefinition.Allocation.Percentile)
{
cancellationToken.ThrowIfCancellationRequested();

if (TargetingEvaluator.IsTargeted(
targetingContext,
percentile.From,
Expand Down Expand Up @@ -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('.'))
{
//
Expand Down