Skip to content

C# Feature Flags Quickstart

This guide gets you from zero to evaluating a feature flag in a C# application. The SDK targets .NET 8.0, .NET 10.0, and .NET Standard 2.0, so it works with .NET 8+, .NET Framework 4.6.1+, and .NET Core 2.0+.

  • A Featureflip account with at least one feature flag created
  • An SDK key from your environment settings
  • .NET 8.0 SDK or later (also supports .NET Standard 2.0 for .NET Framework 4.6.1+)
Terminal window
dotnet add package Featureflip.Client
using Featureflip.Client;
var options = new FeatureFlagOptions
{
BaseUrl = "https://eval.featureflip.io",
WaitForInitialization = true
};
using var client = FeatureflipClient.Get("your-sdk-key", options);

Setting WaitForInitialization = true causes the constructor to block until the initial flag configuration is fetched. The client throws FeatureFlagInitializationException if initialization fails.

If you prefer, set the FEATUREFLIP_SDK_KEY environment variable and omit the sdkKey parameter:

using var client = FeatureflipClient.Get(options: options);
var context = new EvaluationContext { UserId = "user-123" };
bool showBanner = client.BoolVariation("new-banner", context, defaultValue: false);
if (showBanner)
{
Console.WriteLine("Showing the new banner");
}
else
{
Console.WriteLine("Using the default experience");
}

The defaultValue argument is returned when the flag is not found or evaluation fails.

Other variation methods are available for different value types:

string color = client.StringVariation("banner-color", context, defaultValue: "blue");
double limit = client.DoubleVariation("rate-limit", context, defaultValue: 100.0);

The client implements IDisposable. The using statement in the initialization example ensures the client flushes pending analytics events and stops background connections when it goes out of scope.

If you are managing the client lifetime manually, call Dispose() explicitly:

client.Dispose();

The C# SDK implements IDisposable and is designed to live as a long-lived singleton — create one FeatureflipClient at startup and share it across your application. In ASP.NET Core, register the instance in DI so all requests share one client with one streaming connection. Creating a client per request would open thousands of redundant SSE connections.

On initialization, the client fetches the full flag configuration over HTTPS, then maintains a background Task that holds an SSE streaming connection for near-real-time updates. If SSE is unavailable, it falls back to a Timer-based polling loop every 30 seconds. All variation methods (BoolVariation, StringVariation, etc.) read from a ConcurrentDictionary, so they are thread-safe and return immediately without async overhead — no need to await flag evaluations in your controller actions.

The SDK targets .NET Standard 2.0 and runs on .NET 8+ and .NET Framework 4.6.2+. Call Dispose() during application shutdown (ASP.NET Core handles this automatically for singleton registrations) to close the SSE connection and flush pending analytics events. If the streaming connection drops, the SDK continues returning the last known flag values while it reconnects in the background.

FeatureFlagInitializationException on startup

This means the SDK could not fetch the initial flag configuration. Check that your SDK key is correct and matches the target environment. Verify that your application can reach eval.featureflip.io over HTTPS — corporate proxies and firewalls are common blockers. If your app uses HttpClientFactory, the SDK creates its own HttpClient internally, so proxy settings in HttpClient do not apply.

Flags return default values after successful init

Flag keys are case-sensitive — new-banner and New-Banner are different flags. Verify the key in the dashboard matches your code exactly, and confirm the flag is enabled for the environment your SDK key belongs to.

ObjectDisposedException when evaluating flags

This happens when you call variation methods after the client has been disposed. Make sure the using statement or Dispose() call happens at the end of your application lifecycle, not prematurely. In ASP.NET Core, register the client as a singleton in the DI container to manage its lifetime.