Skip to content

IFeatureFlagService Interface Reference

Overview

IFeatureFlagService is the primary service interface for managing feature flags in Flaggy. It provides a comprehensive set of methods for checking flag status, retrieving values, and performing CRUD operations. This service automatically handles cache invalidation for all modifications.

Namespace: Flaggy.Abstractions

Core Methods

IsEnabledAsync

Checks whether a feature flag is enabled.

Task<bool> IsEnabledAsync(string key, CancellationToken cancellationToken = default);

Parameters: - key (string): The unique identifier for the feature flag - cancellationToken (CancellationToken, optional): Token to cancel the async operation

Returns: Task<bool> - True if the flag exists and is enabled, false otherwise

Example:

var flagService = serviceProvider.GetRequiredService<IFeatureFlagService>();

if (await flagService.IsEnabledAsync("new-checkout-flow"))
{
    // Use new checkout flow
    return GetNewCheckoutFlow();
}
else
{
    // Use legacy checkout flow
    return GetLegacyCheckoutFlow();
}

Use Cases: - Feature toggling in controllers or services - A/B testing implementations - Progressive rollout of new features


GetValueAsync (String)

Retrieves the string value of a feature flag with an optional default value.

Task<string?> GetValueAsync(string key, string? defaultValue = null, CancellationToken cancellationToken = default);

Parameters: - key (string): The unique identifier for the feature flag - defaultValue (string, optional): Value returned if flag is not found - cancellationToken (CancellationToken, optional): Token to cancel the async operation

Returns: Task<string?> - The flag's value, default value, or null

Example:

// Get payment gateway with default
var paymentGateway = await flagService.GetValueAsync("payment-gateway", "default-gateway");

// Route to appropriate payment provider
if (paymentGateway == "stripe")
{
    return ProcessStripePayment();
}
else if (paymentGateway == "paypal")
{
    return ProcessPayPalPayment();
}
else
{
    return ProcessDefaultPayment();
}

Use Cases: - Configuration values tied to features - Storing provider selections - Environment-specific feature configuration


GetValueAsync\<T>

Retrieves a typed value from a feature flag. Supports value types (structs).

Task<T?> GetValueAsync<T>(string key, T? defaultValue = null, CancellationToken cancellationToken = default) where T : struct;

Type Parameters: - T: A struct type (int, double, bool, etc.)

Parameters: - key (string): The unique identifier for the feature flag - defaultValue (T, optional): Value returned if flag is not found - cancellationToken (CancellationToken, optional): Token to cancel the async operation

Returns: Task<T?> - The flag's value as type T, default value, or null

Example:

// Get integer value for rate limit
var rateLimit = await flagService.GetValueAsync<int>("api-rate-limit", defaultValue: 100);
ApplyRateLimit(rateLimit.Value);

// Get double value for discount percentage
var discountPercent = await flagService.GetValueAsync<double>("sale-discount", defaultValue: 0.0);
ApplyDiscount(discountPercent.Value);

// Get boolean value
var enableBetaUI = await flagService.GetValueAsync<bool>("beta-ui-enabled", defaultValue: false);

Use Cases: - Numeric thresholds (rate limits, timeouts, quotas) - Percentage values (discounts, probabilities) - Boolean configuration flags


GetFlagAsync

Retrieves a complete feature flag object including metadata.

Task<FeatureFlag?> GetFlagAsync(string key, CancellationToken cancellationToken = default);

Parameters: - key (string): The unique identifier for the feature flag - cancellationToken (CancellationToken, optional): Token to cancel the async operation

Returns: Task<FeatureFlag?> - The complete FeatureFlag object or null if not found

Example:

var flag = await flagService.GetFlagAsync("new-dashboard");

if (flag != null)
{
    Console.WriteLine($"Flag: {flag.Key}");
    Console.WriteLine($"Enabled: {flag.IsEnabled}");
    Console.WriteLine($"Value: {flag.Value}");
    Console.WriteLine($"Description: {flag.Description}");
    Console.WriteLine($"Created: {flag.CreatedAt}");
    Console.WriteLine($"Updated: {flag.UpdatedAt}");
}

Use Cases: - Admin dashboards displaying flag details - Auditing flag history (CreatedAt, UpdatedAt) - Migrating flag values to other systems


GetAllFlagsAsync

Retrieves all feature flags in the system.

Task<IEnumerable<FeatureFlag>> GetAllFlagsAsync(CancellationToken cancellationToken = default);

Parameters: - cancellationToken (CancellationToken, optional): Token to cancel the async operation

Returns: Task<IEnumerable<FeatureFlag>> - Collection of all FeatureFlag objects

Example:

var allFlags = await flagService.GetAllFlagsAsync();

Console.WriteLine("All Feature Flags:");
foreach (var flag in allFlags)
{
    var status = flag.IsEnabled ? "✓" : "✗";
    Console.WriteLine($"  [{status}] {flag.Key}: {flag.Description}");
}

Use Cases: - Admin panels and dashboards - Initialization and startup verification - Bulk operations on flags


RefreshCacheAsync

Forces a refresh of the internal cache by reloading all flags from the provider.

Task RefreshCacheAsync(CancellationToken cancellationToken = default);

Parameters: - cancellationToken (CancellationToken, optional): Token to cancel the async operation

Example:

// After external flag modification (direct database update)
await flagService.RefreshCacheAsync();

// Now get latest values
var flag = await flagService.GetFlagAsync("feature-key");

Use Cases: - Synchronizing with external updates to flags - Manual cache invalidation after batch operations - Debugging cache consistency issues


CRUD Operations

CreateFlagAsync

Creates a new feature flag in the system.

Task<bool> CreateFlagAsync(FeatureFlag flag, CancellationToken cancellationToken = default);

Parameters: - flag (FeatureFlag): The feature flag to create - cancellationToken (CancellationToken, optional): Token to cancel the async operation

Returns: Task<bool> - True if created successfully, false otherwise

Example:

var newFlag = new FeatureFlag
{
    Key = "new-checkout-flow",
    IsEnabled = false,
    Description = "Enable new checkout flow",
    Value = null
};

bool created = await flagService.CreateFlagAsync(newFlag);
if (created)
{
    Console.WriteLine("Flag created successfully");
}
else
{
    Console.WriteLine("Failed to create flag (may already exist)");
}

Use Cases: - Adding new features to flag management - Initializing flags at application startup - Creating flags programmatically


UpdateFlagAsync

Updates an existing feature flag.

Task<bool> UpdateFlagAsync(FeatureFlag flag, CancellationToken cancellationToken = default);

Parameters: - flag (FeatureFlag): The feature flag with updated values - cancellationToken (CancellationToken, optional): Token to cancel the async operation

Returns: Task<bool> - True if updated successfully, false if flag not found

Example:

var flag = await flagService.GetFlagAsync("new-checkout-flow");
if (flag != null)
{
    flag.IsEnabled = true;
    flag.Value = "v2-optimized";
    flag.Description = "Enable new checkout flow - optimized version";

    bool updated = await flagService.UpdateFlagAsync(flag);
    if (updated)
    {
        Console.WriteLine("Flag updated successfully");
    }
}

Use Cases: - Toggling flags on/off - Updating flag configuration values - Changing flag descriptions


DeleteFlagAsync

Deletes a feature flag from the system.

Task<bool> DeleteFlagAsync(string key, CancellationToken cancellationToken = default);

Parameters: - key (string): The unique identifier of the flag to delete - cancellationToken (CancellationToken, optional): Token to cancel the async operation

Returns: Task<bool> - True if deleted successfully, false if flag not found

Example:

bool deleted = await flagService.DeleteFlagAsync("deprecated-feature");
if (deleted)
{
    Console.WriteLine("Flag deleted successfully");
}
else
{
    Console.WriteLine("Flag not found");
}

Use Cases: - Removing deprecated features - Cleanup of temporary flags - Archive management


Common Patterns

Pattern 1: Feature Toggle

public class PricingController
{
    private readonly IFeatureFlagService _flagService;

    public PricingController(IFeatureFlagService flagService)
    {
        _flagService = flagService;
    }

    public async Task<IActionResult> GetPricing()
    {
        if (await _flagService.IsEnabledAsync("dynamic-pricing"))
        {
            return Ok(GetDynamicPricing());
        }
        return Ok(GetStaticPricing());
    }

    private object GetDynamicPricing() => new { /* dynamic pricing logic */ };
    private object GetStaticPricing() => new { /* static pricing logic */ };
}

Pattern 2: Configuration Values

public class NotificationService
{
    private readonly IFeatureFlagService _flagService;

    public NotificationService(IFeatureFlagService flagService)
    {
        _flagService = flagService;
    }

    public async Task SendNotificationAsync(string userId, string message)
    {
        var provider = await _flagService.GetValueAsync("notification-provider", "email");

        switch (provider)
        {
            case "sms":
                await SendSmsAsync(userId, message);
                break;
            case "push":
                await SendPushAsync(userId, message);
                break;
            default:
                await SendEmailAsync(userId, message);
                break;
        }
    }
}

Pattern 3: Admin Management

[ApiController]
[Route("api/[controller]")]
public class FeatureFlagsController : ControllerBase
{
    private readonly IFeatureFlagService _flagService;

    public FeatureFlagsController(IFeatureFlagService flagService)
    {
        _flagService = flagService;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<FeatureFlag>>> GetAll()
    {
        var flags = await _flagService.GetAllFlagsAsync();
        return Ok(flags);
    }

    [HttpPost]
    public async Task<ActionResult<bool>> Create(FeatureFlag flag)
    {
        var created = await _flagService.CreateFlagAsync(flag);
        return created ? Ok(true) : BadRequest("Failed to create flag");
    }

    [HttpPut("{key}")]
    public async Task<ActionResult<bool>> Update(string key, FeatureFlag flag)
    {
        flag.Key = key;
        var updated = await _flagService.UpdateFlagAsync(flag);
        return updated ? Ok(true) : NotFound();
    }

    [HttpDelete("{key}")]
    public async Task<ActionResult<bool>> Delete(string key)
    {
        var deleted = await _flagService.DeleteFlagAsync(key);
        return deleted ? Ok(true) : NotFound();
    }
}

For convenience methods and additional functionality, see: - Extension Methods: FeatureFlagServiceExtensions - Models: FeatureFlag Model - Provider: IFeatureFlagProvider Interface

All modification methods (Create, Update, Delete) automatically trigger cache invalidation to ensure consistency across the application.