Skip to content

Support contextual variant service provider and feature status fallback - #611

Open
zhiyuanliang-ms wants to merge 1 commit into
mainfrom
zhiyuanliang/contextual-vsp
Open

Support contextual variant service provider and feature status fallback#611
zhiyuanliang-ms wants to merge 1 commit into
mainfrom
zhiyuanliang/contextual-vsp

Conversation

@zhiyuanliang-ms

@zhiyuanliang-ms zhiyuanliang-ms commented Jul 29, 2026

Copy link
Copy Markdown
Member

Why this PR?

#604 #608

IVariantServiceProvider<TService>.GetServiceAsync currently does not accept a context, which limits it to scenarios that rely on ambient context.

This creates a capability gap between VariantServiceProvider and IVariantFeatureManager, because both IVariantFeatureManager.IsEnabledAsync and IVariantFeatureManager.GetVariantAsync provide overloads that accept an explicit context.

How to fix

This PR introduces IContextualVariantServiceProvider<TService> with method GetServiceAsync<TContext>(TContext context, CancellationToken cancellationToken)

The PR also adds WithVariantService<TService, TEnabled, TDisabled>(featureName) which supports falling back to a service based on the feature’s enabled or disabled status.

Service resolution behavior

Service resolution follows these steps:

  1. Resolve the assigned variant.
  • When the supplied context implements ITargetingContext, pass it to GetVariantAsync.
  • Otherwise, resolve the variant without an explicit context.
  • GetVariantAsync only accepts ITargetingContext, so a non-targeting context is not used during variant resolution.
  1. If a variant is assigned and a matching service is registered, return that service.
  2. Otherwise, fall back to the feature status.
  • If the feature is enabled, return TEnabled.
  • If the feature is disabled, return TDisabled.

Because IsEnabledAsync accepts an arbitrary TContext, the feature-status fallback honors the supplied context even when it does not implement ITargetingContext.

Copilot AI review requested due to automatic review settings July 29, 2026 09:46

ServiceProvider serviceProvider = services.BuildServiceProvider();

IVariantFeatureManager featureManager = serviceProvider.GetRequiredService<IVariantFeatureManager>();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

featureManager can be removed

Comment on lines +105 to +112
if (useContext)
{
enabled = await _featureManager.IsEnabledAsync(_featureName, context, cancellationToken);
}
else
{
enabled = await _featureManager.IsEnabledAsync(_featureName, cancellationToken);
}

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR expands the variant-service injection capabilities in the Feature Management .NET SDK by introducing a contextual variant service provider API and adding an optional “feature enabled/disabled” fallback path when no variant-based service can be resolved.

Changes:

  • Introduces IContextualVariantServiceProvider<TService> and updates the internal VariantServiceProvider<TService> to support context-aware evaluation.
  • Adds WithVariantService<TService, TEnabled, TDisabled>(featureName) to allow falling back to an enabled/disabled implementation when variant resolution fails.
  • Refactors and extends tests into a dedicated VariantServiceProviderTest suite, including new coverage for contextual behavior and feature-status fallback.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Tests.FeatureManagement/VariantServices.cs Adds alias-based test implementations used by new variant/fallback tests.
tests/Tests.FeatureManagement/VariantServiceProviderTest.cs New test suite covering variant DI, keyed service resolution, contextual provider behavior, and status fallback.
tests/Tests.FeatureManagement/FeatureManagementTest.cs Removes variant service provider tests that were moved to the new dedicated test file.
tests/Tests.FeatureManagement/AppContext.cs Adds an additional context type for tests (currently unused).
src/Microsoft.FeatureManagement/VariantServiceProvider.cs Implements contextual service retrieval and optional feature-status fallback.
src/Microsoft.FeatureManagement/IContextualVariantServiceProvider.cs New public interface for contextual variant service providers.
src/Microsoft.FeatureManagement/FeatureManagementBuilderExtensions.cs Adds new DI builder overload enabling feature-status fallback and registers contextual provider interface.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +101 to +104
//
// No implementation resolved from a variant. Fall back to the feature status.
bool enabled;

Comment on lines +54 to +58
/// <summary>
/// Adds a <see cref="VariantServiceProvider{TService}"/> to the feature management system that falls back to the feature status when no variant is assigned.
/// </summary>
/// <param name="builder">The <see cref="IFeatureManagementBuilder"/> used to customize feature management functionality.</param>
/// <param name="featureName">The feature flag that should be used to determine which implementation of the service should be used. The <see cref="VariantServiceProvider{TService}"/> will return the implementation matching the assigned variant, or, when no variant is assigned, <typeparamref name="TEnabled"/> if the feature is enabled and <typeparamref name="TDisabled"/> if it is disabled.</param>
Comment on lines +14 to +20
/// <summary>
/// Gets an implementation variant of TService, using the provided context to evaluate contextual feature filters when determining the assigned variant.
/// </summary>
/// <typeparam name="TContext">The type of the context.</typeparam>
/// <param name="context">A context that provides information used to evaluate contextual feature filters and to determine which variant will be assigned.</param>
/// <param name="cancellationToken">The cancellation token to cancel the operation.</param>
/// <returns>An implementation of TService.</returns>
Comment on lines +18 to +21
class AccountContext : IAccountContext
{
public string AccountId { get; set; }
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be removed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants