OpenFeature.Providers.MultiProvider 2.11.0

Prefix Reserved
dotnet add package OpenFeature.Providers.MultiProvider --version 2.11.0
                    
NuGet\Install-Package OpenFeature.Providers.MultiProvider -Version 2.11.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OpenFeature.Providers.MultiProvider" Version="2.11.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OpenFeature.Providers.MultiProvider" Version="2.11.0" />
                    
Directory.Packages.props
<PackageReference Include="OpenFeature.Providers.MultiProvider" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add OpenFeature.Providers.MultiProvider --version 2.11.0
                    
#r "nuget: OpenFeature.Providers.MultiProvider, 2.11.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package OpenFeature.Providers.MultiProvider@2.11.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=OpenFeature.Providers.MultiProvider&version=2.11.0
                    
Install as a Cake Addin
#tool nuget:?package=OpenFeature.Providers.MultiProvider&version=2.11.0
                    
Install as a Cake Tool

OpenFeature .NET MultiProvider

NuGet

The MultiProvider is a feature provider that enables the use of multiple underlying providers, allowing different providers to be used for different flag keys or based on specific routing logic. This enables scenarios where different feature flags may be served by different sources or providers within the same application.

Overview

The MultiProvider acts as a composite provider that can delegate flag resolution to different underlying providers based on configuration or routing rules. It supports various evaluation strategies to determine how multiple providers should be evaluated and how their results should be combined.

For more information about the MultiProvider specification, see the OpenFeature Multi Provider specification.

Installation

dotnet add package OpenFeature.Providers.MultiProvider

Usage

The MultiProvider integrates seamlessly with the OpenFeature dependency injection system, allowing you to configure multiple providers using the AddMultiProvider extension method:

using OpenFeature.Providers.MultiProvider.DependencyInjection;

builder.Services.AddOpenFeature(featureBuilder =>
{
    featureBuilder
        .AddMultiProvider("multi-provider", multiProviderBuilder =>
        {
            // Add providers using factory methods for proper DI integration
            multiProviderBuilder
                .AddProvider("primary", sp => new YourPrimaryProvider())
                .AddProvider("fallback", sp => new YourFallbackProvider())
                .UseStrategy<FirstMatchStrategy>();
        });
});

// Retrieve and use the client
var featureClient = openFeatureApi.GetClient("multi-provider");
var result = await featureClient.GetBooleanValueAsync("my-flag", false);
Adding Providers with DI

The MultiProviderBuilder provides several methods to add providers:

Using Factory Methods:

multiProviderBuilder
    .AddProvider("provider-name", sp => new InMemoryProvider(flags))
    .AddProvider("another-provider", sp => sp.GetRequiredService<SomeProvider>());

Using Provider Instances:

var provider = new InMemoryProvider(flags);
multiProviderBuilder.AddProvider("provider-name", provider);

Using Generic Type Resolution:

// Provider will be resolved from DI container
multiProviderBuilder.AddProvider<YourProvider>("provider-name");

// Or with custom factory
multiProviderBuilder.AddProvider<YourProvider>("provider-name", sp => new YourProvider(config));
Configuring Evaluation Strategy

Specify an evaluation strategy using any of these methods:

// Using generic type
multiProviderBuilder.UseStrategy<FirstMatchStrategy>();

// Using factory method with DI
multiProviderBuilder.UseStrategy(sp => new FirstMatchStrategy());

// Using strategy instance
multiProviderBuilder.UseStrategy(new ComparisonStrategy());
Using with Named Domains

Configure the MultiProvider for a specific domain:

featureBuilder
    .AddMultiProvider("production-domain", multiProviderBuilder =>
    {
        multiProviderBuilder
            .AddProvider("remote", sp => new RemoteProvider())
            .AddProvider("cache", sp => new CacheProvider())
            .UseStrategy<FirstSuccessfulStrategy>();
    });

Basic Setup

For scenarios where dependency injection is not available, you can use the traditional setup:

using OpenFeature;
using OpenFeature.Providers.MultiProvider;

// Create your individual providers
var primaryProvider = new YourPrimaryProvider();
var fallbackProvider = new YourFallbackProvider();

// Create provider entries
var providerEntries = new[]
{
    new ProviderEntry(primaryProvider, "primary"),
    new ProviderEntry(fallbackProvider, "fallback")
};

// Create and set the MultiProvider
var multiProvider = new MultiProvider(providerEntries);
await Api.Instance.SetProviderAsync(multiProvider);

// Use the client as normal
var client = Api.Instance.GetClient();
var result = await client.GetBooleanValueAsync("my-flag", false);

Evaluation Strategies

The MultiProvider supports several evaluation strategies to determine how providers are evaluated:

1. FirstMatchStrategy (Default)

Returns the first result that does not indicate "flag not found". Providers are evaluated sequentially in the order they were configured.

using OpenFeature.Providers.MultiProvider.Strategies;

var strategy = new FirstMatchStrategy();
var multiProvider = new MultiProvider(providerEntries, strategy);
2. FirstSuccessfulStrategy

Returns the first result that does not result in an error. If any provider returns an error, it's ignored as long as there is a successful result.

using OpenFeature.Providers.MultiProvider.Strategies;

var strategy = new FirstSuccessfulStrategy();
var multiProvider = new MultiProvider(providerEntries, strategy);
3. ComparisonStrategy

Evaluates all providers and compares their results. Useful for testing or validation scenarios where you want to ensure providers return consistent values.

using OpenFeature.Providers.MultiProvider.Strategies;

var strategy = new ComparisonStrategy();
var multiProvider = new MultiProvider(providerEntries, strategy);

Advanced Configuration

Named Providers

You can assign names to providers for better identification and debugging:

var providerEntries = new[]
{
    new ProviderEntry(new ProviderA(), "provider-a"),
    new ProviderEntry(new ProviderB(), "provider-b"),
    new ProviderEntry(new ProviderC(), "provider-c")
};
Custom Evaluation Context

The MultiProvider respects evaluation context and passes it to underlying providers:

var context = EvaluationContext.Builder()
    .Set("userId", "user123")
    .Set("environment", "production")
    .Build();

var result = await client.GetBooleanValueAsync("feature-flag", false, context);

Use Cases

Primary/Fallback Configuration

Use multiple providers with fallback capabilities:

var providerEntries = new[]
{
    new ProviderEntry(new RemoteProvider(), "remote"),
    new ProviderEntry(new LocalCacheProvider(), "cache"),
    new ProviderEntry(new StaticProvider(), "static")
};

var multiProvider = new MultiProvider(providerEntries, new FirstSuccessfulStrategy());

A/B Testing Provider Comparison

Compare results from different providers for testing purposes:

var providerEntries = new[]
{
    new ProviderEntry(new ProviderA(), "provider-a"),
    new ProviderEntry(new ProviderB(), "provider-b")
};

var multiProvider = new MultiProvider(providerEntries, new ComparisonStrategy());

Migration Scenarios

Gradually migrate from one provider to another:

var providerEntries = new[]
{
    new ProviderEntry(new NewProvider(), "new-provider"),
    new ProviderEntry(new LegacyProvider(), "legacy-provider")
};

var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy());

Error Handling

The MultiProvider handles errors from underlying providers according to the chosen evaluation strategy:

  • FirstMatchStrategy: Throws errors immediately when encountered
  • FirstSuccessfulStrategy: Ignores errors if there's a successful result, throws all errors if all providers fail
  • ComparisonStrategy: Collects and reports all errors for analysis

Thread Safety

The MultiProvider is thread-safe and can be used concurrently across multiple threads. It properly handles initialization and shutdown of underlying providers.

Lifecycle Management

The MultiProvider manages the lifecycle of all registered providers:

// Initialize all providers
await multiProvider.InitializeAsync(context);

// Shutdown all providers
await multiProvider.ShutdownAsync();

// Dispose (implements IAsyncDisposable)
await multiProvider.DisposeAsync();

Events

The MultiProvider supports OpenFeature events and provides specification-compliant event handling. It follows the OpenFeature Multi-Provider specification for event handling behavior.

Event Handling Example

using OpenFeature;
using OpenFeature.Providers.MultiProvider;

// Create the MultiProvider with multiple providers
var providerEntries = new[]
{
    new ProviderEntry(new ProviderA(), "provider-a"),
    new ProviderEntry(new ProviderB(), "provider-b")
};
var multiProvider = new MultiProvider(providerEntries);

// Subscribe to MultiProvider events
Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, (eventDetails) =>
{
    Console.WriteLine($"MultiProvider is ready: {eventDetails?.ProviderName}");
});

Api.Instance.AddHandler(ProviderEventTypes.ProviderStale, (eventDetails) =>
{
    Console.WriteLine($"MultiProvider became stale: {eventDetails?.Message}");
});

Api.Instance.AddHandler(ProviderEventTypes.ProviderConfigurationChanged, (eventDetails) =>
{
    Console.WriteLine($"Configuration changed - Flags: {string.Join(", ", eventDetails?.FlagsChanged ?? [])}");
});

Api.Instance.AddHandler(ProviderEventTypes.ProviderError, (eventDetails) =>
{
    Console.WriteLine($"MultiProvider error: {eventDetails?.Message}");
});

// Set the provider - this will initialize all underlying providers
// and emit PROVIDER_READY when all are successfully initialized
await Api.Instance.SetProviderAsync(multiProvider);

// Later, if an underlying provider becomes stale and changes MultiProvider status:
// Only then will a PROVIDER_STALE event be emitted from MultiProvider

Event Lifecycle

  1. During Initialization:

    • MultiProvider emits PROVIDER_READY when all underlying providers initialize successfully
    • MultiProvider emits PROVIDER_ERROR if any providers fail to initialize (causing aggregate status to become ERROR/FATAL)
  2. Runtime Status Changes:

    • Status-changing events from underlying providers are captured internally
    • MultiProvider only emits events when its aggregate status changes due to these internal events
    • Example: If MultiProvider is READY and one provider becomes STALE, MultiProvider emits PROVIDER_STALE
  3. Configuration Changes:

    • PROVIDER_CONFIGURATION_CHANGED events from underlying providers are always re-emitted

Requirements

  • .NET 8+
  • .NET Framework 4.6.2+
  • .NET Standard 2.0+

Contributing

See the OpenFeature .NET SDK contributing guide for details on how to contribute to this project.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 is compatible.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.11.0 25 12/18/2025
2.10.0 669 12/1/2025
2.9.0 631 10/16/2025