Use when you have a written implementation plan to execute in a separate session with review checkpoints
npx skills add featbit/featbit-skills --skill "featbit-dotnet-sdk"
Install specific skill from multi-skill repository
# Description
Expert guidance for integrating FeatBit .NET Server SDK in .NET applications. Use when user asks about ".NET SDK", "C# feature flags", "ASP.NET Core FeatBit", "dependency injection", "console app integration", or mentions .cs, .csproj, Program.cs files.
# SKILL.md
name: featbit-dotnet-sdk
description: Expert guidance for integrating FeatBit .NET Server SDK in .NET applications. Use when user asks about ".NET SDK", "C# feature flags", "ASP.NET Core FeatBit", "dependency injection", "console app integration", or mentions .cs, .csproj, Program.cs files.
license: MIT
metadata:
author: FeatBit
version: 2.0.0
category: sdk-integration
FeatBit .NET Server SDK Integration
Expert guidance for integrating the FeatBit .NET Server-Side SDK into .NET applications, including ASP.NET Core, console applications, and worker services.
When to Use This Skill
Activate when users:
- Ask about .NET SDK integration or setup
- Need dependency injection configuration for ASP.NET Core
- Want to evaluate feature flags in C# code
- Ask about console applications, worker services, or background services
- Need examples of flag variations (bool, string, int, double, JSON)
- Want to implement A/B testing with custom events
- Mention offline mode or bootstrapping from JSON
Prerequisites
Before integration, obtain:
- Environment Secret: How to get it
- SDK URLs: How to get them
Quick Start
Installation
dotnet add package FeatBit.ServerSdk
Basic Console App Example
using FeatBit.Sdk.Server;
using FeatBit.Sdk.Server.Model;
using FeatBit.Sdk.Server.Options;
// Setup SDK options
var options = new FbOptionsBuilder("<replace-with-your-env-secret>")
.Event(new Uri("https://app-eval.featbit.co"))
.Streaming(new Uri("wss://app-eval.featbit.co"))
.Build();
// Create client instance
var client = new FbClient(options);
if (!client.Initialized)
{
Console.WriteLine("FbClient failed to initialize. Using fallback values.");
}
// Create user
var user = FbUser.Builder("user-key-123")
.Name("User Name")
.Custom("role", "admin")
.Build();
// Evaluate feature flag
var isEnabled = client.BoolVariation("game-runner", user, defaultValue: false);
Console.WriteLine($"Feature enabled: {isEnabled}");
// Close client before exit
await client.CloseAsync();
ASP.NET Core Integration
Setup with Dependency Injection
using FeatBit.Sdk.Server.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// Register FeatBit service (uses singleton pattern)
builder.Services.AddFeatBit(options =>
{
options.EnvSecret = "<replace-with-your-env-secret>";
options.StreamingUri = new Uri("wss://app-eval.featbit.co");
options.EventUri = new Uri("https://app-eval.featbit.co");
options.StartWaitTime = TimeSpan.FromSeconds(3);
options.DisableEvents = true; // Optional: disable event tracking
});
var app = builder.Build();
app.MapControllers();
app.Run();
Using in Controllers
using FeatBit.Sdk.Server;
using FeatBit.Sdk.Server.Model;
using Microsoft.AspNetCore.Mvc;
public class HomeController : ControllerBase
{
private readonly IFbClient _fbClient;
public HomeController(IFbClient fbClient)
{
_fbClient = fbClient;
}
[HttpGet("check-feature")]
public IActionResult CheckFeature()
{
// Authenticated user
var user = FbUser.Builder(User.Identity?.Name ?? "anonymous")
.Name(User.Identity?.Name)
.Custom("role", "admin")
.Custom("country", "US")
.Build();
var isEnabled = _fbClient.BoolVariation("new-feature", user, defaultValue: false);
return Ok(new { featureEnabled = isEnabled });
}
[HttpGet("public-feature")]
public IActionResult PublicFeature()
{
// Anonymous user
var sessionId = HttpContext.Session?.Id ?? Guid.NewGuid().ToString();
var anonymousUser = FbUser.Builder($"anonymous-{sessionId}").Build();
var hasAccess = _fbClient.BoolVariation("beta-access", anonymousUser, false);
return Ok(new { betaAccess = hasAccess });
}
}
FbClient Overview
Client Lifecycle
ASP.NET Core: Registered as singleton via DI, managed automatically
Console Apps: Create one instance, reuse throughout lifetime, call CloseAsync() before exit
Worker Services: Inject via DI, same lifecycle as ASP.NET Core
Custom Configuration Options
using FeatBit.Sdk.Server.Options;
using Microsoft.Extensions.Logging;
var loggerFactory = LoggerFactory.Create(x => x.AddConsole());
var options = new FbOptionsBuilder("<your-env-secret>")
.Streaming(new Uri("wss://app-eval.featbit.co"))
.Event(new Uri("https://app-eval.featbit.co"))
.StartWaitTime(TimeSpan.FromSeconds(3))
.DisableEvents(true)
.LoggerFactory(loggerFactory)
.Build();
var client = new FbClient(options);
Logging Support
SDK supports standard .NET logging via Microsoft.Extensions.Logging:
// Create logger factory with desired providers
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
// Pass to SDK
var options = new FbOptionsBuilder(secret)
.LoggerFactory(loggerFactory)
.Build();
In ASP.NET Core, AddFeatBit() automatically uses the host's logger factory.
FbUser: User Context
Building Users
FbUser defines user attributes for flag evaluation. The key is mandatory and must uniquely identify each user.
// Minimal user
var user = FbUser.Builder("unique-user-key").Build();
// User with built-in and custom attributes
var user = FbUser.Builder("user-123")
.Name("Bob Smith")
.Custom("age", "15")
.Custom("country", "FR")
.Custom("subscription", "premium")
.Build();
Built-in attributes: key (required), name
Custom attributes: Any key-value pairs for targeting rules and analytics
Evaluating Flags
The SDK evaluates flags locally using cached data synchronized via WebSocket. No network call per evaluation.
Available Variation Methods
// Boolean
var flag = _fbClient.BoolVariation("feature-key", user, defaultValue: false);
// String
var theme = _fbClient.StringVariation("theme-key", user, defaultValue: "default");
// Integer
var maxItems = _fbClient.IntVariation("max-items", user, defaultValue: 10);
// Double
var discount = _fbClient.DoubleVariation("discount-rate", user, defaultValue: 0.0);
// Float (similar to Double)
var ratio = _fbClient.FloatVariation("ratio-key", user, defaultValue: 1.0f);
// JSON (use StringVariation for JSON strings)
var configJson = _fbClient.StringVariation("config-key", user, defaultValue: "{}");
var config = JsonSerializer.Deserialize<MyConfig>(configJson);
Variation with Evaluation Detail
Get flag value plus evaluation metadata:
var detail = _fbClient.BoolVariationDetail("feature-key", user, defaultValue: false);
Console.WriteLine($"Value: {detail.Value}");
Console.WriteLine($"Reason: {detail.Kind} - {detail.Reason}");
Default Values
Always provide default values. They're used when:
- SDK is not initialized
- Flag doesn't exist
- Network issues occur
- Evaluation fails
Experiments (A/B Testing)
Track custom events for experiments and analytics:
// Track event without value
_fbClient.Track(user, "purchase-completed");
// Track event with numeric value (default is 1.0)
_fbClient.Track(user, "revenue", 99.99);
Important: Call Track() AFTER evaluating the related feature flag.
Advanced Scenarios
Worker Service Integration
using FeatBit.Sdk.Server;
using FeatBit.Sdk.Server.DependencyInjection;
using Microsoft.Extensions.Hosting;
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
// Configure FeatBit from appsettings.json or inline
services.AddFeatBit(options =>
{
options.EnvSecret = hostContext.Configuration["FeatBit:EnvSecret"]
?? "<your-env-secret>";
options.StreamingUri = new Uri(
hostContext.Configuration["FeatBit:StreamingUri"]
?? "wss://app-eval.featbit.co");
options.EventUri = new Uri(
hostContext.Configuration["FeatBit:EventUri"]
?? "https://app-eval.featbit.co");
options.StartWaitTime = TimeSpan.FromSeconds(3);
});
services.AddHostedService<Worker>();
});
}
public class Worker : BackgroundService
{
private readonly IFbClient _fbClient;
private readonly ILogger<Worker> _logger;
public Worker(IFbClient fbClient, ILogger<Worker> logger)
{
_fbClient = fbClient;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var user = FbUser.Builder("worker-instance").Build();
var shouldProcess = _fbClient.BoolVariation("enable-processing", user, true);
if (shouldProcess)
{
_logger.LogInformation("Processing task at: {time}", DateTimeOffset.Now);
// Do work here
}
else
{
_logger.LogInformation("Processing disabled by feature flag");
}
await Task.Delay(60000, stoppingToken); // Wait 1 minute
}
}
}
appsettings.json configuration:
{
"FeatBit": {
"EnvSecret": "your-env-secret",
"StreamingUri": "wss://app-eval.featbit.co",
"EventUri": "https://app-eval.featbit.co"
}
}
Offline Mode
Stop remote calls and optionally bootstrap from JSON:
var options = new FbOptionsBuilder()
.Offline(true)
.Build();
var client = new FbClient(options);
Bootstrapping from JSON (only in offline mode):
# Get current flags from server
curl -H "Authorization: <env-secret>" \
http://localhost:5100/api/public/sdk/server/latest-all > featbit-bootstrap.json
var json = File.ReadAllText("featbit-bootstrap.json");
var options = new FbOptionsBuilder()
.Offline(true)
.UseJsonBootstrapProvider(json)
.Build();
var client = new FbClient(options);
Disable Event Collection
Disable automatic events while staying online:
var options = new FbOptionsBuilder()
.DisableEvents(true)
.Build();
Common Use Cases
Gradual Rollout
var user = FbUser.Builder(userId).Build();
var useNewPayment = _fbClient.BoolVariation("new-payment-processor", user, false);
return useNewPayment
? await _newPaymentService.ProcessAsync(payment)
: await _legacyPaymentService.ProcessAsync(payment);
Maintenance Mode
var systemUser = FbUser.Builder("system").Build();
var isMaintenance = _fbClient.BoolVariation("maintenance-mode", systemUser, false);
if (isMaintenance)
return StatusCode(503, "Service under maintenance");
Remote Configuration
// Simple numeric configuration
var user = FbUser.Builder(userId).Build();
var maxRetries = _fbClient.IntVariation("max-retry-attempts", user, 3);
var timeout = _fbClient.IntVariation("api-timeout-seconds", user, 30);
// Complex JSON configuration
var configJson = _fbClient.StringVariation("app-config", user, "{}");
var appConfig = JsonSerializer.Deserialize<AppConfig>(configJson);
// Use the configuration
var httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(appConfig.TimeoutSeconds)
};
Example JSON configuration:
{
"timeoutSeconds": 30,
"maxRetries": 3,
"enableCaching": true,
"cacheExpiryMinutes": 60,
"apiEndpoint": "https://api.example.com",
"features": {
"enableLogging": true,
"logLevel": "Information"
}
}
AppConfig model:
public class AppConfig
{
public int TimeoutSeconds { get; set; } = 30;
public int MaxRetries { get; set; } = 3;
public bool EnableCaching { get; set; } = true;
public int CacheExpiryMinutes { get; set; } = 60;
public string ApiEndpoint { get; set; } = "https://api.example.com";
public FeatureSettings Features { get; set; } = new();
}
public class FeatureSettings
{
public bool EnableLogging { get; set; } = true;
public string LogLevel { get; set; } = "Information";
}
A/B Testing
var user = FbUser.Builder(userId).Build();
var checkoutFlow = _fbClient.StringVariation("checkout-flow", user, "original");
if (purchaseSuccessful)
{
_fbClient.Track(user, "purchase-completed");
_fbClient.Track(user, "revenue", purchaseAmount);
}
Troubleshooting
Client Not Initializing:
- Verify EnvSecret is correct
- Check network connectivity to FeatBit server
- Ensure WebSocket connections are allowed (firewall)
- Increase StartWaitTime if initialization is slow
Flags Not Updating:
- Confirm WebSocket connection is active (check logs)
- Ensure SDK is not in offline mode
- Verify server logs for connection errors
Events Not Tracked:
- Check DisableEvents is false
- Verify EventUri is accessible
- Confirm network connectivity
Platform Support
This SDK targets:
- .NET 8.0+: Runs on .NET 6.0 and higher
- .NET Core 3.1+: Runs on .NET Core 3.1 and later
- .NET Framework 4.6.2+: Runs on .NET Framework 4.6.2 and above
- .NET Standard 2.0/2.1: Runs in any .NET Standard 2.x project
Note: System.Text.Json is required and included as a dependency for platforms that don't include it.
Official Resources
- GitHub: https://github.com/featbit/featbit-dotnet-sdk
- NuGet: https://www.nuget.org/packages/FeatBit.ServerSdk
- Documentation: https://docs.featbit.co/sdk-docs/server-side-sdks/dotnet
- Getting Started: https://docs.featbit.co/getting-started/connect-an-sdk#net
- Examples: https://github.com/featbit/featbit-samples
Support
- Slack Community: Join FeatBit Slack
- Issues: Submit on GitHub
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.