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.
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.
dotnet add package OpenFeature.Providers.MultiProviderusing 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);The MultiProvider supports several evaluation strategies to determine how providers are evaluated:
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);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);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);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")
};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 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());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());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());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
The MultiProvider is thread-safe and can be used concurrently across multiple threads. It properly handles initialization and shutdown of underlying providers.
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();The MultiProvider supports OpenFeature events and provides specification-compliant event handling. It follows the OpenFeature Multi-Provider specification for event handling behavior.
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-
During Initialization:
- MultiProvider emits
PROVIDER_READYwhen all underlying providers initialize successfully - MultiProvider emits
PROVIDER_ERRORif any providers fail to initialize (causing aggregate status to become ERROR/FATAL)
- MultiProvider emits
-
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
-
Configuration Changes:
PROVIDER_CONFIGURATION_CHANGEDevents from underlying providers are always re-emitted
- .NET 8+
- .NET Framework 4.6.2+
- .NET Standard 2.0+
See the OpenFeature .NET SDK contributing guide for details on how to contribute to this project.