SDKs

Flagbearer for .NET

The .NET SDK for Flagbearer. Targets .NET 8 or later.

Install

dotnet add package Flagbearer

Keys

Use a server key, which starts with fbs_. Server keys are secret: read them from configuration or the environment, such as FLAGBEARER_SERVER_KEY, and never put them in browser code or in the repository. Browsers use client keys, which start with fbc_, through @flagbearer/web.

Sync at startup

Create one client per process, when the app starts, and wait for it to sync before accepting requests:

using Flagbearer;

var flags = new FlagbearerClient(Environment.GetEnvironmentVariable("FLAGBEARER_SERVER_KEY")!);

try
{
    using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
    await flags.SyncAsync(timeout.Token);
}
catch (Exception error)
{
    // Keep starting: checks use their defaults, and the SDK retries in the background.
    Console.Error.WriteLine($"Initial Flagbearer sync failed: {error.Message}");
}

In ASP.NET Core, register it as a singleton and sync before the app starts serving:

builder.Services.AddSingleton(_ => new FlagbearerClient(
    builder.Configuration["Flagbearer:ServerKey"]!));

var app = builder.Build();
try
{
    await app.Services.GetRequiredService<FlagbearerClient>().SyncAsync();
}
catch (FlagbearerException error)
{
    app.Logger.LogWarning(error, "Initial Flagbearer sync failed");
}

The container disposes the client on shutdown.

Check per request

Pass each request's user explicitly, and a default:

app.MapGet("/search", (HttpContext context, FlagbearerClient flags) =>
{
    var user = new User(Key: context.User.FindFirst("sub")?.Value, Email: context.User.FindFirst("email")?.Value);
    var advanced = flags.IsEnabled("advanced-search", user, defaultValue: false);
    // …
});

The email is optional. Include it to turn flags on for testers by email. The default is used until the client has synced, and when the flag doesn't exist.

Shut down

Keep the client for the life of the process, not per request. Dispose it on shutdown:

await flags.DisposeAsync();

Serverless functions should call await flags.FlushAsync() at the end of each invocation.