### Basic OpenFeature Usage Example Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md This C# example demonstrates how to set up an InMemoryProvider, get a FeatureClient, and evaluate a boolean feature flag. Ensure to handle potential exceptions during provider setup. ```csharp public async Task Example() { // Register your feature flag provider try { await Api.Instance.SetProviderAsync(new InMemoryProvider()); } catch (Exception ex) { // Log error } // Create a new client FeatureClient client = Api.Instance.GetClient(); // Evaluate your feature flag bool v2Enabled = await client.GetBooleanValueAsync("v2_enabled", false); if ( v2Enabled ) { // Do some work } } ``` -------------------------------- ### Run the application Source: https://github.com/open-feature/dotnet-sdk/blob/main/samples/AspNetCore/README.md Execute the command to start the .NET 9 web application. ```shell dotnet run ``` -------------------------------- ### Install OpenFeature.Hosting Package Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Command to add the OpenFeature.Hosting package to a .NET project, enabling dependency injection and hosting capabilities for OpenFeature. ```sh dotnet add package OpenFeature.Hosting ``` -------------------------------- ### Basic MultiProvider Setup without DI Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Set up the MultiProvider manually when dependency injection is not available. Create individual providers, then combine them into provider entries for the MultiProvider. ```csharp using 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); ``` -------------------------------- ### Install MultiProvider Package Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Add the MultiProvider package to your .NET project using the dotnet CLI. ```shell dotnet add package OpenFeature.Providers.MultiProvider ``` -------------------------------- ### Update Program.cs - After Migration Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.DependencyInjection/README.md Example of Program.cs configuration after migrating to OpenFeature.Hosting, with AddHostedFeatureLifecycle removed. ```csharp builder.Services.AddOpenFeature(featureBuilder => { // Omit for code brevity }); ``` -------------------------------- ### Migration Scenario Provider Setup Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Implement a migration strategy using the MultiProvider and FirstMatchStrategy. This allows for a gradual transition from a legacy provider to a new one. ```csharp var providerEntries = new[] { new ProviderEntry(new NewProvider(), "new-provider"), new ProviderEntry(new LegacyProvider(), "legacy-provider") }; var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy()); ``` -------------------------------- ### Update Program.cs - Before Migration Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.DependencyInjection/README.md Example of Program.cs configuration before migrating from OpenFeature.DependencyInjection, including the AddHostedFeatureLifecycle call. ```csharp builder.Services.AddOpenFeature(featureBuilder => { featureBuilder .AddHostedFeatureLifecycle(); // Omit for code brevity }); ``` -------------------------------- ### Dependency Injection Setup with MultiProvider Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Configure the MultiProvider using dependency injection with AddMultiProvider. Providers can be added using factory methods for proper DI integration. Use the FirstMatchStrategy by default. ```csharp using OpenFeature.Providers.MultiProvider.DependencyInjection; builder.Services.AddOpenFeature(featureBuilder => { featureBuilder .AddMultiProvider("multi-provider", multiProviderBuilder => { // Add providers using factory methods for proper DI integration multiProviderBuilder .AddProvider("primary", sp => new YourPrimaryProvider()) .AddProvider("fallback", sp => new YourFallbackProvider()) .UseStrategy(); }); }); // Retrieve and use the client var featureClient = openFeatureApi.GetClient("multi-provider"); var result = await featureClient.GetBooleanValueAsync("my-flag", false); ``` -------------------------------- ### Configure Domain-Scoped Providers with Selection Policy Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Set up multiple providers with a custom policy to select the default provider. This example designates 'name1' as the default. ```csharp builder.Services.AddOpenFeature(featureBuilder => { featureBuilder .AddContext((contextBuilder, serviceProvider) => { /* Custom context configuration */ }) .AddHook((serviceProvider) => new LoggingHook( /* Custom configuration */ )) .AddHook(new MetricsHook()) .AddInMemoryProvider("name1") .AddInMemoryProvider("name2") .AddPolicyName(options => { // Custom logic to select a default provider options.DefaultNameSelector = serviceProvider => "name1"; }); }); ``` -------------------------------- ### A/B Testing Provider Comparison Setup Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Configure a MultiProvider with the ComparisonStrategy for A/B testing. This allows for comparing results from different providers to ensure consistency. ```csharp var providerEntries = new[] { new ProviderEntry(new ProviderA(), "provider-a"), new ProviderEntry(new ProviderB(), "provider-b") }; var multiProvider = new MultiProvider(providerEntries, new ComparisonStrategy()); ``` -------------------------------- ### Add OpenFeature.Hosting Package Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.DependencyInjection/README.md Update or install the latest OpenFeature.Hosting package to replace the deprecated dependency. ```xml ``` -------------------------------- ### FirstMatchStrategy Example Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Instantiate and use the FirstMatchStrategy with a MultiProvider. This strategy evaluates providers sequentially and returns the first successful result. ```csharp using OpenFeature.Providers.MultiProvider.Strategies; var strategy = new FirstMatchStrategy(); var multiProvider = new MultiProvider(providerEntries, strategy); ``` -------------------------------- ### Example Usage of MetricsHook Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Demonstrates how to set up and use the MetricsHook with the OpenFeature .NET SDK and the Flagd provider. Metrics are sent to the console via OpenTelemetry. ```csharp using System.Threading.Tasks; using OpenFeature.Contrib.Providers.Flagd; using OpenFeature; using OpenFeature.Hooks; using OpenTelemetry; using OpenTelemetry.Metrics; namespace OpenFeatureTestApp { class Hello { static async Task Main(string[] args) { // set up the OpenTelemetry OTLP exporter var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter("OpenFeature") .ConfigureResource(r => r.AddService("openfeature-test")) .AddConsoleExporter() .Build(); // add the MetricsHook to the OpenFeature instance OpenFeature.Api.Instance.AddHooks(new MetricsHook()); var flagdProvider = new FlagdProvider(new Uri("http://localhost:8013")); // Set the flagdProvider as the provider for the OpenFeature SDK await OpenFeature.Api.Instance.SetProviderAsync(flagdProvider); var client = OpenFeature.Api.Instance.GetClient("my-app"); var val = await client.GetBooleanValueAsync("myBoolFlag", false); // Print the value of the 'myBoolFlag' feature flag System.Console.WriteLine(val); } } } ``` -------------------------------- ### Add OpenFeature Package Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Install the OpenFeature SDK package into your .NET project using the dotnet CLI. ```sh dotnet add package OpenFeature ``` -------------------------------- ### Implement a Custom OpenFeature Provider in C# Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Implement the FeatureProvider interface to create a custom provider. This example shows how to define metadata and resolve various flag types. ```csharp public class MyProvider : FeatureProvider { public override Metadata GetMetadata() { return new Metadata("My Provider"); } public override Task> ResolveBooleanValueAsync(string flagKey, bool defaultValue, EvaluationContext? context = null, CancellationToken cancellationToken = default) { // resolve a boolean flag value } public override Task> ResolveStringValueAsync(string flagKey, string defaultValue, EvaluationContext? context = null, CancellationToken cancellationToken = default) { // resolve a string flag value } public override Task> ResolveIntegerValueAsync(string flagKey, int defaultValue, EvaluationContext? context = null, CancellationToken cancellationToken = default) { // resolve an int flag value } public override Task> ResolveDoubleValueAsync(string flagKey, double defaultValue, EvaluationContext? context = null, CancellationToken cancellationToken = default) { // resolve a double flag value } public override Task> ResolveStructureValueAsync(string flagKey, Value defaultValue, EvaluationContext? context = null, CancellationToken cancellationToken = default) { // resolve an object flag value } } ``` -------------------------------- ### Build and Publish NativeAOT Application Source: https://github.com/open-feature/dotnet-sdk/blob/main/docs/AOT_COMPATIBILITY.md Commands to build your project with AOT analysis and then publish it as a self-contained native executable. The final command shows an example of running the compiled application. ```bash # Build with AOT analysis dotnet build -c Release # Publish as native executable dotnet publish -c Release # Run the native executable (example path for macOS ARM64) ./bin/Release/net9.0/osx-arm64/publish/MyApp ``` -------------------------------- ### Implement a Custom OpenFeature Hook in C# Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Implement the Hook interface to create custom hooks. This example defines the Before, After, Error, and Finally stages. ```csharp public class MyHook : Hook { public override ValueTask BeforeAsync(HookContext context, IReadOnlyDictionary? hints = null, CancellationToken cancellationToken = default) { // code to run before flag evaluation } public override ValueTask AfterAsync(HookContext context, FlagEvaluationDetails details, IReadOnlyDictionary? hints = null, CancellationToken cancellationToken = default) { // code to run after successful flag evaluation } public override ValueTask ErrorAsync(HookContext context, Exception error, IReadOnlyDictionary? hints = null, CancellationToken cancellationToken = default) { // code to run if there's an error during before hooks or during flag evaluation } public override ValueTask FinallyAsync(HookContext context, FlagEvaluationDetails evaluationDetails, IReadOnlyDictionary? hints = null, CancellationToken cancellationToken = default) { // code to run after all other stages, regardless of success/failure } } ``` -------------------------------- ### Register a Domain-Scoped Custom Provider Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Register a domain-scoped custom provider to enable configurations specific to each domain. This example uses a domain-specific feature key. ```csharp services.AddOpenFeature(builder => { builder.AddProvider("my-domain", (provider, domain) => { // Resolve services or configurations as needed for the domain var variants = new Dictionary { { "on", true } }; var flags = new Dictionary { { $"{domain}-feature-key", new Flag(variants, "on") } }; // Register a domain-scoped custom provider such as InMemoryProvider return new InMemoryProvider(flags); }); }); ``` -------------------------------- ### Basic OpenFeature Usage in NativeAOT Source: https://github.com/open-feature/dotnet-sdk/blob/main/docs/AOT_COMPATIBILITY.md Demonstrates standard OpenFeature API usage, including getting the API instance, client, and evaluating boolean, string, and integer flags. This code is fully compatible with NativeAOT. ```csharp using OpenFeature; using OpenFeature.Model; // Basic OpenFeature usage - fully AOT compatible var api = Api.Instance; var client = api.GetClient("my-app"); // All flag evaluation methods work var boolFlag = await client.GetBooleanValueAsync("feature-enabled", false); var stringFlag = await client.GetStringValueAsync("welcome-message", "Hello"); var intFlag = await client.GetIntegerValueAsync("max-items", 10); ``` -------------------------------- ### ASP.NET Core Integration with In-Memory Provider and Logging Hook Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Hosting/README.md Integrate OpenFeature with an ASP.NET Core application using an in-memory provider and a logging hook. This example demonstrates basic feature flag evaluation within a web request. ```csharp var builder = WebApplication.CreateBuilder(args); builder.Services.AddOpenFeature(featureBuilder => { featureBuilder .AddInMemoryProvider() .AddHook(); }); 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(); ``` -------------------------------- ### Navigate to ASP.NET Core Sample Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Change directory to the ASP.NET Core sample application folder. ```sh cd samples/AspNetCore ``` -------------------------------- ### Navigate to the Web sample project directory Source: https://github.com/open-feature/dotnet-sdk/blob/main/samples/AspNetCore/README.md Change the current directory to the AspNetCore sample project. ```shell cd openfeature-dotnet-sdk/samples/AspNetCore ``` -------------------------------- ### Navigate to Console Sample Directory Source: https://github.com/open-feature/dotnet-sdk/blob/main/samples/Console/README.md Change the current directory to the console sample project within the cloned repository. ```shell cd openfeature-dotnet-sdk/samples/Console ``` -------------------------------- ### Initialize Console Project Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Use this command to create a new .NET console application project. ```sh dotnet new console ``` -------------------------------- ### Initialize FirstSuccessfulStrategy Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Instantiate a MultiProvider using the FirstSuccessfulStrategy. This strategy returns the first successful result, ignoring any errors from other providers. ```csharp using OpenFeature.Providers.MultiProvider.Strategies; var strategy = new FirstSuccessfulStrategy(); var multiProvider = new MultiProvider(providerEntries, strategy); ``` -------------------------------- ### Multi-Provider with ComparisonStrategy Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Demonstrates instantiating a Multi-Provider with the ComparisonStrategy, which evaluates all providers in parallel and compares their results. ```csharp // Basic comparison var multiProvider = new MultiProvider(providerEntries, new ComparisonStrategy()); ``` ```csharp // With fallback provider var multiProvider = new MultiProvider(providerEntries, new ComparisonStrategy(fallbackProvider: provider1)); ``` ```csharp // With mismatch callback var multiProvider = new MultiProvider(providerEntries, new ComparisonStrategy(onMismatch: (mismatchDetails) => { // Log or handle mismatches between providers foreach (var kvp in mismatchDetails) { Console.WriteLine($"Provider {kvp.Key}: {kvp.Value}"); } })); ``` -------------------------------- ### Run Benchmarks Locally Source: https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md Commands to restore dependencies, build the release configuration, and run benchmarks locally. ```bash dotnet restore dotnet build --configuration Release --output "./release" --no-restore dotnet release/OpenFeature.Benchmarks.dll ``` -------------------------------- ### Register Providers with Domains Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Illustrates how to register providers, including assigning them to specific domains. Clients can then be retrieved associated with either the default provider or a domain-specific provider. ```csharp using OpenFeature.Provider; try { // registering the default provider await Api.Instance.SetProviderAsync(new LocalProvider()); // registering a provider to a domain await Api.Instance.SetProviderAsync("clientForCache", new CachedProvider()); } catch (Exception ex) { // Log error } // a client backed by default provider FeatureClient clientDefault = Api.Instance.GetClient(); // a client backed by CachedProvider FeatureClient scopedClient = Api.Instance.GetClient("clientForCache"); ``` -------------------------------- ### Navigate to Repository Directory Source: https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md Change your current directory to the cloned repository folder to begin working on contributions. ```bash cd openfeature-dotnet-sdk ``` -------------------------------- ### Initialize ComparisonStrategy Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Instantiate a MultiProvider using the ComparisonStrategy. This strategy evaluates all providers and compares their results, useful for testing and validation. ```csharp using OpenFeature.Providers.MultiProvider.Strategies; var strategy = new ComparisonStrategy(); var multiProvider = new MultiProvider(providerEntries, strategy); ``` -------------------------------- ### Subscribe to MultiProvider Events Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Demonstrates how to subscribe to various events emitted by the MultiProvider. This includes handling provider readiness, staleness, configuration changes, and errors. Ensure the OpenFeature API instance is initialized before setting handlers. ```csharp 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 ``` -------------------------------- ### Configure Project for NativeAOT Source: https://github.com/open-feature/dotnet-sdk/blob/main/docs/AOT_COMPATIBILITY.md Add these properties to your .csproj file to enable NativeAOT compilation. Ensure you are targeting a compatible .NET version. ```xml net8.0 Exe true ``` -------------------------------- ### Using TraceEnricherHook with Flagd Provider Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Demonstrates setting up OpenTelemetry, adding the TraceEnricherHook, configuring the Flagd provider, and evaluating a feature flag. Traces are sent to a Jaeger OTLP collector. ```csharp using System.Threading.Tasks; using OpenFeature.Contrib.Providers.Flagd; using OpenFeature.Hooks; using OpenTelemetry.Exporter; using OpenTelemetry.Resources; using OpenTelemetry; using OpenTelemetry.Trace; namespace OpenFeatureTestApp { class Hello { static async Task Main(string[] args) { // set up the OpenTelemetry OTLP exporter var tracerProvider = Sdk.CreateTracerProviderBuilder() .AddSource("my-tracer") .ConfigureResource(r => r.AddService("jaeger-test")) .AddOtlpExporter(o => { o.ExportProcessorType = ExportProcessorType.Simple; }) .Build(); // add the TraceEnricherHook to the OpenFeature instance OpenFeature.Api.Instance.AddHooks(new TraceEnricherHook()); var flagdProvider = new FlagdProvider(new Uri("http://localhost:8013")); // Set the flagdProvider as the provider for the OpenFeature SDK await OpenFeature.Api.Instance.SetProviderAsync(flagdProvider); var client = OpenFeature.Api.Instance.GetClient("my-app"); var val = await client.GetBooleanValueAsync("myBoolFlag", false); // Print the value of the 'myBoolFlag' feature flag System.Console.WriteLine(val); } } } ``` -------------------------------- ### Configuring Evaluation Strategy with Instance Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Specify an evaluation strategy for the MultiProvider by providing an instance of the strategy directly. ```csharp multiProviderBuilder.UseStrategy(new ComparisonStrategy()); ``` -------------------------------- ### Run NativeAOT Compatibility Test Source: https://github.com/open-feature/dotnet-sdk/blob/main/docs/AOT_COMPATIBILITY.md Navigate to the AOT compatibility test project directory and publish it as a native executable. This command verifies the SDK's compatibility by compiling and running tests natively. ```bash cd test/OpenFeature.AotCompatibility dotnet publish -c Release ./bin/Release/net9.0/[runtime]/publish/OpenFeature.AotCompatibility ``` -------------------------------- ### Clone the repository Source: https://github.com/open-feature/dotnet-sdk/blob/main/samples/AspNetCore/README.md Clone the OpenFeature .NET SDK repository to your local machine. ```shell git clone https://github.com/open-feature/dotnet-sdk.git openfeature-dotnet-sdk ``` -------------------------------- ### Primary/Fallback Provider Configuration Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Set up a MultiProvider with a primary and fallback providers using the FirstSuccessfulStrategy. This ensures a value is always returned, prioritizing the primary provider. ```csharp 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()); ``` -------------------------------- ### Run Unit Tests Source: https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md Execute all unit tests for the project. This helps ensure that your changes do not break existing functionality. ```bash dotnet test test/OpenFeature.Tests/ ``` -------------------------------- ### Add Your Fork as a Remote Source: https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md Configure your local repository to push changes to your personal fork. Replace YOUR_GITHUB_USERNAME with your actual GitHub username. ```bash git remote add fork https://github.com/YOUR_GITHUB_USERNAME/dotnet-sdk.git ``` -------------------------------- ### Adding Providers with Instances Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Add providers to the MultiProviderBuilder by providing an instance of the provider directly. ```csharp var provider = new InMemoryProvider(flags); multiProviderBuilder.AddProvider("provider-name", provider); ``` -------------------------------- ### Basic Multi-Provider Usage Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Demonstrates how to create and set a Multi-Provider with an InMemoryProvider and use it with the OpenFeature API. The FirstMatchStrategy is used by default. ```csharp using OpenFeature.Providers.MultiProvider; using OpenFeature.Providers.MultiProvider.Models; using OpenFeature.Providers.MultiProvider.Strategies; // Create provider entries var providerEntries = new List { new(new InMemoryProvider(provider1Flags), "Provider1"), new(new InMemoryProvider(provider2Flags), "Provider2") }; // Create multi-provider with FirstMatchStrategy (default) var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy()); // Set as the default provider await Api.Instance.SetProviderAsync(multiProvider); // Use normally - the multi-provider will handle delegation var client = Api.Instance.GetClient(); var flagValue = await client.GetBooleanValueAsync("my-flag", false); ``` -------------------------------- ### Run the Console Application Source: https://github.com/open-feature/dotnet-sdk/blob/main/samples/Console/README.md Execute the console application using the .NET CLI. ```shell dotnet app.cs ``` -------------------------------- ### MultiProvider Lifecycle Management Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Manage the lifecycle of the MultiProvider and its registered providers, including initialization, shutdown, and disposal. ```csharp // Initialize all providers await multiProvider.InitializeAsync(context); // Shutdown all providers await multiProvider.ShutdownAsync(); // Dispose (implements IAsyncDisposable) await multiProvider.DisposeAsync(); ``` -------------------------------- ### Authenticate with GitHub CLI Source: https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md Log in to GitHub CLI with the necessary scopes to read packages. This process involves obtaining a personal access token and verifying authentication status. ```console $ gh auth login --scopes read:packages ? What account do you want to log into? GitHub.com ? What is your preferred protocol for Git operations? HTTPS ? How would you like to authenticate GitHub CLI? Login with a web browser ! First copy your one-time code: ****-**** Press Enter to open github.com in your browser... ✓ Authentication complete. - gh config set -h github.com git_protocol https ✓ Configured git protocol ✓ Logged in as ******** ``` ```console $ gh auth status github.com ✓ Logged in to github.com as ******** (~/.config/gh/hosts.yml) ✓ Git operations for github.com configured to use https protocol. ✓ Token: gho_************************************ ✓ Token scopes: gist, read:org, read:packages, repo, workflow ``` -------------------------------- ### Run End-to-End Tests Source: https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md Execute the end-to-end tests for the SDK. This verifies the integration and behavior of the SDK in a more complete environment. ```bash dotnet test test/OpenFeature.E2ETests/ ``` -------------------------------- ### Run Unit Tests with Code Coverage Source: https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md Run unit tests and generate a code coverage report in OpenCover format. This is useful for assessing the thoroughness of your tests. ```bash dotnet test test/OpenFeature.Tests/ --coverlet --coverlet-output-format opencover ``` -------------------------------- ### Initialize Git Submodules for E2E Tests Source: https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md Before running end-to-end tests, initialize and update all necessary git submodules. This ensures that all required test resources are available. ```bash git submodule update --init --recursive ``` -------------------------------- ### Configure Global Context, Hooks, and Event Handlers Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Hosting/README.md Configure global evaluation context, hooks, and event handlers when registering OpenFeature. This allows for custom context configuration and reaction to provider lifecycle events. ```csharp builder.Services.AddOpenFeature(featureBuilder => { featureBuilder .AddContext((contextBuilder, serviceProvider) => { // Custom context configuration }) .AddHook() .AddHandler(ProviderEventTypes.ProviderReady, (eventDetails) => { // Handle provider ready event }); }); ``` -------------------------------- ### Configure Logging Hook for Debugging Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Demonstrates how to attach the LoggingHook to a client to log detailed information during flag evaluation. Ensure your log level is set to 'debug' and a console logger is configured. ```csharp using OpenFeature.Contrib.Hooks.Logging; using Microsoft.Extensions.Logging; using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); var logger = loggerFactory.CreateLogger("Program"); var client = Api.Instance.GetClient(); client.AddHooks(new LoggingHook(logger)); ``` -------------------------------- ### Configure OpenFeature with Context, Hooks, and Handlers Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Register OpenFeature with custom context, hooks, and event handlers for advanced control. This allows for global or API-level configurations. ```csharp builder.Services.AddOpenFeature(featureBuilder => { featureBuilder .AddContext((contextBuilder, serviceProvider) => { /* Custom context configuration */ }) .AddHook() .AddHandler(ProviderEventTypes.ProviderReady, (eventDetails) => { /* Handle event */ }); }); ``` -------------------------------- ### Configuring Evaluation Strategy with Factory Method Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Specify an evaluation strategy for the MultiProvider using a factory method that resolves dependencies from the service provider. ```csharp multiProviderBuilder.UseStrategy(sp => new FirstMatchStrategy()); ``` -------------------------------- ### Register a Custom Provider with Flags Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Register a custom provider, like InMemoryProvider, using AddProvider. This method allows dynamic resolution of services or configurations during registration. ```csharp services.AddOpenFeature(builder => { builder.AddProvider(provider => { // Resolve services or configurations as needed var variants = new Dictionary { { "on", true } }; var flags = new Dictionary { { "feature-key", new Flag(variants, "on") } }; // Register a custom provider, such as InMemoryProvider return new InMemoryProvider(flags); }); }); ``` -------------------------------- ### Multi-Provider with FirstMatchStrategy Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Instantiates a Multi-Provider using the FirstMatchStrategy, which evaluates providers sequentially and returns the first non-flag-not-found result. ```csharp var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy()); ``` -------------------------------- ### Set Targeting Context for Flag Evaluation Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Demonstrates how to set global, client, and invocation-level evaluation contexts for flag targeting. Ensure the flag management system supports targeting and provides input data via the evaluation context. ```csharp using OpenFeature.Model; // set a value to the global context EvaluationContextBuilder builder = EvaluationContext.Builder(); builder.Set("region", "us-east-1"); EvaluationContext apiCtx = builder.Build(); Api.Instance.SetContext(apiCtx); // set a value to the client context builder = EvaluationContext.Builder(); builder.Set("region", "us-east-1"); EvaluationContext clientCtx = builder.Build(); var client = Api.Instance.GetClient(); client.SetContext(clientCtx); // set a value to the invocation context builder = EvaluationContext.Builder(); builder.Set("region", "us-east-1"); EvaluationContext reqCtx = builder.Build(); bool flagValue = await client.GetBooleanValueAsync("some-flag", false, reqCtx); ``` -------------------------------- ### Adding Providers with Factory Methods Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Add providers to the MultiProviderBuilder using factory methods, which accept a service provider to resolve dependencies. ```csharp multiProviderBuilder .AddProvider("provider-name", sp => new InMemoryProvider(flags)) .AddProvider("another-provider", sp => sp.GetRequiredService()); ``` -------------------------------- ### Configure NuGet Source for GitHub Packages Source: https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md Update your local NuGet configuration to include a new source for Open Feature packages from GitHub Packages. This command uses your GitHub email and authentication token. ```console $ dotnet nuget update source github-open-feature --username $(gh api user --jq .email) --password $(gh auth token) --store-password-in-clear-text Package source "github-open-feature" was successfully updated. ``` -------------------------------- ### Register a Custom Provider using a Factory Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Hosting/README.md Register a custom provider using a factory function. This allows for resolving services or configuration as needed during provider instantiation. ```csharp builder.Services.AddOpenFeature(featureBuilder => { featureBuilder.AddProvider(provider => { // Resolve services or configuration as needed return new MyCustomProvider(); }); }); ``` -------------------------------- ### Register Multiple Domain-Scoped Providers Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Hosting/README.md Register multiple providers and select a default provider by domain. This is useful for multi-tenancy or environment separation. ```csharp builder.Services.AddOpenFeature(featureBuilder => { featureBuilder .AddInMemoryProvider("default") .AddInMemoryProvider("beta") .AddPolicyName(options => { options.DefaultNameSelector = serviceProvider => "default"; }); }); ``` -------------------------------- ### Register Hooks for Flag Evaluation Lifecycle Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Shows how to add custom logic at different stages of the flag evaluation process. Hooks can be registered globally, per client, or for a single flag evaluation. ```csharp // add a hook globally, to run on all evaluations Api.Instance.AddHooks(new ExampleGlobalHook()); // add a hook on this client, to run on all evaluations made by this client var client = Api.Instance.GetClient(); client.AddHooks(new ExampleClientHook()); // add a hook for this evaluation only var value = await client.GetBooleanValueAsync("boolFlag", false, context, new FlagEvaluationOptions(new ExampleInvocationHook())); ``` -------------------------------- ### Configuring MetricsHook with Custom Dimensions Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Shows how to add custom dimensions to all metrics emitted by the MetricsHook by providing MetricsHookOptions during hook initialization. ```csharp var options = MetricsHookOptions.CreateBuilder() .WithCustomDimension("custom_dimension_key", "custom_dimension_value") .Build(); OpenFeature.Api.Instance.AddHooks(new MetricsHook(options)); ``` -------------------------------- ### Register OpenFeature with AddInMemoryProvider Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Hosting/README.md Register OpenFeature in your application's dependency injection container using the AddInMemoryProvider method. This is typically done in Program.cs for ASP.NET Core applications. ```csharp builder.Services.AddOpenFeature(featureBuilder => { featureBuilder .AddInMemoryProvider(); }); ``` -------------------------------- ### Set OpenFeature Provider Asynchronously Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Registers a custom provider with the OpenFeature API. Handles potential exceptions during provider initialization. ```csharp try { await Api.Instance.SetProviderAsync(new MyProvider()); } catch (Exception ex) { // Log error } ``` -------------------------------- ### Handle Provider Events Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Define a callback function to process provider events and register it for specific event types like PROVIDER_READY. ```csharp public static void EventHandler(ProviderEventPayload eventDetails) { Console.WriteLine(eventDetails.Type); } ``` ```csharp EventHandlerDelegate callback = EventHandler; // add an implementation of the EventHandlerDelegate for the PROVIDER_READY event Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, callback); ``` -------------------------------- ### Configuring MetricsHook with Custom Flag Evaluation Metadata Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Demonstrates how to provide a callback to extract custom flag evaluation metadata using WithFlagEvaluationMetadata in MetricsHookOptions. ```csharp var options = MetricsHookOptions.CreateBuilder() .WithFlagEvaluationMetadata("boolean", s => s.GetBool("boolean")) .Build(); ``` -------------------------------- ### Configuring MultiProvider for a Specific Domain Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Configure the MultiProvider to be associated with a specific domain, allowing for domain-specific provider configurations and strategies. ```csharp featureBuilder .AddMultiProvider("production-domain", multiProviderBuilder => { multiProviderBuilder .AddProvider("remote", sp => new RemoteProvider()) .AddProvider("cache", sp => new CacheProvider()) .UseStrategy(); }); ``` -------------------------------- ### Create a New Feature Branch Source: https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md Create a new branch for your feature or bugfix. Replace NAME_OF_FEATURE with a descriptive name for your changes. After making changes, commit them and push to your fork. ```bash git checkout -b feat/NAME_OF_FEATURE # Make your changes git commit git push fork feat/NAME_OF_FEATURE ``` -------------------------------- ### Track User Actions with Feature Flags Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Associate user actions and their associated details with feature flag evaluations using the client's Track function. This is useful for experimentation and analytics. ```csharp var client = Api.Instance.GetClient(); client.Track("visited-promo-page", trackingEventDetails: TrackingEventDetails.Builder().SetValue(99.77).Set("currency", "USD").Build()); ``` -------------------------------- ### OpenFeature Hook for Measuring Evaluation Duration in C# Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md This hook demonstrates using hook data to pass information between stages. It measures and logs the time elapsed between the Before and After stages. ```csharp class TimingHook : Hook { public override ValueTask BeforeAsync(HookContext context, IReadOnlyDictionary? hints = null, CancellationToken cancellationToken = default) { context.Data.Set("beforeTime", DateTime.Now); return ValueTask.FromResult(context.EvaluationContext); } public override ValueTask AfterAsync(HookContext context, FlagEvaluationDetails details, IReadOnlyDictionary? hints = null, CancellationToken cancellationToken = default) { var beforeTime = context.Data.Get("beforeTime") as DateTime?; var duration = DateTime.Now - beforeTime; Console.WriteLine($"Duration: {duration}"); return ValueTask.CompletedTask; } } ``` -------------------------------- ### Resolve Specific Provider Client using FromKeyedServices Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Hosting/README.md If multiple providers are registered, specify which client and provider to resolve by using the [FromKeyedServices] attribute. This allows for targeted feature flag evaluation based on provider keys. ```csharp 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(); ``` -------------------------------- ### Configuring TraceEnricherHook with Custom Metadata Extraction Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Demonstrates providing a callback to WithFlagEvaluationMetadata to extract custom flag evaluation data and add it as a tag to the span. ```csharp var options = TraceEnricherHookOptions.CreateBuilder() .WithFlagEvaluationMetadata("boolean", s => s.GetBool("boolean")) .Build(); ``` -------------------------------- ### Configuring TraceEnricherHook with Custom Tags Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Shows how to add custom tags to spans generated by the TraceEnricherHook using TraceEnricherHookOptions. ```csharp var options = TraceEnricherHookOptions.CreateBuilder() .WithTag("custom_dimension_key", "custom_dimension_value") .Build(); OpenFeature.Api.Instance.AddHooks(new TraceEnricherHook(options)); ``` -------------------------------- ### AOT-Compatible JSON Serialization Source: https://github.com/open-feature/dotnet-sdk/blob/main/docs/AOT_COMPATIBILITY.md For optimal NativeAOT performance, use the provided `JsonSerializerContext` for serializing and deserializing OpenFeature model objects like `Value`. This avoids reflection-based issues. ```csharp using System.Text.Json; using OpenFeature.Model; using OpenFeature.Serialization; var value = new Value(Structure.Builder() .Set("name", "test") .Set("enabled", true) .Build()); // Use AOT-compatible serialization var json = JsonSerializer.Serialize(value, OpenFeatureJsonSerializerContext.Default.Value); var deserialized = JsonSerializer.Deserialize(json, OpenFeatureJsonSerializerContext.Default.Value); ``` -------------------------------- ### Configuring Evaluation Strategy with Generic Type Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Specify an evaluation strategy for the MultiProvider using its generic type. ```csharp multiProviderBuilder.UseStrategy(); ``` -------------------------------- ### Configure Named Providers Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Assign names to providers when creating ProviderEntry objects for better identification and debugging within the MultiProvider. ```csharp var providerEntries = new[] { new ProviderEntry(new ProviderA(), "provider-a"), new ProviderEntry(new ProviderB(), "provider-b"), new ProviderEntry(new ProviderC(), "provider-c") }; ``` -------------------------------- ### Register Event Handler for Specific Client Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Attach an event handler to a specific OpenFeature client instance after setting its provider. This allows for client-scoped event management. ```csharp EventHandlerDelegate callback = EventHandler; var myClient = Api.Instance.GetClient("my-client"); try { var provider = new ExampleProvider(); await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name, provider); } catch (Exception ex) { // Log error } myClient.AddHandler(ProviderEventTypes.ProviderReady, callback); ``` -------------------------------- ### Register AsyncLocal Transaction Context Propagator Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Set up the AsyncLocalTransactionContextPropagator to automatically propagate transaction-specific evaluation context across asynchronous operations. ```csharp // registering the AsyncLocalTransactionContextPropagator Api.Instance.SetTransactionContextPropagator(new AsyncLocalTransactionContextPropagator()); ``` -------------------------------- ### Remove OpenFeature.DependencyInjection Package Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.DependencyInjection/README.md Remove the existing OpenFeature.DependencyInjection package reference from your project file. ```xml ``` -------------------------------- ### Shut Down All OpenFeature Providers Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Gracefully clean up all registered OpenFeature providers by calling the ShutdownAsync method. This should be used during application termination. ```csharp // Shut down all providers await Api.Instance.ShutdownAsync(); ``` -------------------------------- ### Use Custom Evaluation Context Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Pass a custom evaluation context to the MultiProvider, which will then be forwarded to the underlying providers during feature flag evaluation. ```csharp var context = EvaluationContext.Builder() .Set("userId", "user123") .Set("environment", "production") .Build(); var result = await client.GetBooleanValueAsync("feature-flag", false, context); ``` -------------------------------- ### Adding Providers with Generic Type Resolution Source: https://github.com/open-feature/dotnet-sdk/blob/main/src/OpenFeature.Providers.MultiProvider/README.md Add providers to the MultiProviderBuilder using their generic type. The provider can be resolved from the DI container or configured with a custom factory. ```csharp // Provider will be resolved from DI container multiProviderBuilder.AddProvider("provider-name"); // Or with custom factory multiProviderBuilder.AddProvider("provider-name", sp => new YourProvider(config)); ``` -------------------------------- ### Set Transaction Context for Flag Evaluations Source: https://github.com/open-feature/dotnet-sdk/blob/main/README.md Manually set transaction context, including details like userId, to be applied to subsequent flag evaluations within the current transaction scope. ```csharp // adding userId to transaction context EvaluationContext transactionContext = EvaluationContext.Builder() .Set("userId", userId) .Build(); Api.Instance.SetTransactionContext(transactionContext); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.