OpenFeature is an open standard for feature flag management, created to support a robust feature flag ecosystem using cloud native technologies. OpenFeature will provide a unified API and SDK, and a developer-first, cloud-native implementation, with extensibility for open source and commercial offerings.
$ dotnet add package OpenFeature.HostingOpenFeature.Hosting is an extension for the OpenFeature .NET SDK that streamlines integration with .NET applications using dependency injection and hosting. It enables seamless configuration and lifecycle management of feature flag providers, hooks, and evaluation context using idiomatic .NET patterns.
🧪 The OpenFeature.Hosting package is still considered experimental and may undergo significant changes. Feedback and contributions are welcome!
Add the package to your project:
dotnet add package OpenFeature.Hosting
Register OpenFeature in your application's dependency injection container (e.g., in Program.cs for ASP.NET Core):
builder.Services.AddOpenFeature(featureBuilder => {
featureBuilder
.AddInMemoryProvider();
});
You can add global evaluation context, hooks, and event handlers as needed:
builder.Services.AddOpenFeature(featureBuilder => {
featureBuilder
.AddContext((contextBuilder, serviceProvider) => {
// Custom context configuration
})
.AddHook<LoggingHook>()
.AddHandler(ProviderEventTypes.ProviderReady, (eventDetails) => {
// Handle provider ready event
});
});
To register multiple providers and select a default provider by domain:
builder.Services.AddOpenFeature(featureBuilder => {
featureBuilder
.AddInMemoryProvider("default")
.AddInMemoryProvider("beta")
.AddPolicyName(options => {
options.DefaultNameSelector = serviceProvider => "default";
});
});
You can register a custom provider using a factory:
builder.Services.AddOpenFeature(featureBuilder => {
featureBuilder.AddProvider(provider => {
// Resolve services or configuration as needed
return new MyCustomProvider();
});
});
Below is a simple example of integrating OpenFeature with an ASP.NET Core application using an in-memory provider and a logging hook.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenFeature(featureBuilder => {
featureBuilder
.AddInMemoryProvider()
.AddHook<LoggingHook>();
});
var app = builder.Build();
app.MapGet("/", async (IFeatureClient client) => {
bool enabled = await client.GetBooleanValueAsync("my-flag", false);
return enabled ? "Feature enabled!" : "Feature disabled.";
});
app.Run();
If you have multiple providers registered, you can specify which client and provider to resolve by using the FromKeyedServices attribute:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenFeature(featureBuilder => {
featureBuilder
.AddInMemoryProvider("default")
.AddInMemoryProvider("beta")
.AddPolicyName(options => {
options.DefaultNameSelector = serviceProvider => "default";
});
});
var app = builder.Build();
app.MapGet("/", async ([FromKeyedServices("beta")] IFeatureClient client) => {
bool enabled = await client.GetBooleanValueAsync("my-flag", false);
return enabled ? "Feature enabled!" : "Feature disabled.";
});
app.Run();
Contributions are welcome! See the CONTRIBUTING guide for details.