Skip to main content

State Change Handlers

Learn how to react to feature flag state changes in your application.

IFeatureStateService​

IFeatureStateService allows registering Action handlers which will be called when the feature changes state.

info

Callbacks follow environment-level AlwaysOn/off state. A percentage, user-targeting, or entity rule is treated as off for these callbacks, even if it evaluates true for a particular request. Use request evaluation for per-user decisions.

Available callbacks​

  • WhenFeatureTurnsOn(string/object featureKey, Action action): runs when a feature flips on (immediately if already on). Returns a Guid for unregistering.
  • WhenFeatureTurnsOff(string/object featureKey, Action action): runs when a feature flips off (immediately if already off). Returns a Guid for unregistering.
  • UnregisterFeatureStateChange(string featureKey, Guid id): removes a previously registered on/off handler.
  • WhenDefinitionsChange(Action action): runs when feature definitions are refreshed (HTTP refresh, snapshot load, or live update).
  • UnregisterDefinitionsChange(Guid id): removes a definitions-change handler.

Examples​

Turn on/off handlers​

var featureStateService = app.Services.GetRequiredService<IFeatureStateService>();

// Subscribe
var onId = featureStateService.WhenFeatureTurnsOn(FeatureFlags.HourlyJob, () =>
{
RecurringJob.AddOrUpdate<ITestRecurringJob>("Hourly job", s => s.RunAsync(), Cron.Hourly());
});

var offId = featureStateService.WhenFeatureTurnsOff(FeatureFlags.HourlyJob, () =>
{
RecurringJob.RemoveIfExists("Hourly job");
});

// Unsubscribe (e.g., during disposal)
featureStateService.UnregisterFeatureStateChange(FeatureFlags.HourlyJob.ToString(), onId);
featureStateService.UnregisterFeatureStateChange(FeatureFlags.HourlyJob.ToString(), offId);

Definitions change handler​

var featureStateService = app.Services.GetRequiredService<IFeatureStateService>();

var defId = featureStateService.WhenDefinitionsChange(() =>
{
// Clear caches, refresh generated docs, etc.
logger.LogInformation("Feature definitions changed. Refreshing dependent resources.");
});

// Unsubscribe when no longer needed
featureStateService.UnregisterDefinitionsChange(defId);

Feature flags around Hangfire jobs​

Install Toggly.FeatureManagement.Hangfire and configure Hangfire storage with AddHangfire first. The extension resolves IRecurringJobManager from dependency injection and keeps the recurring job registered only while the flag has AlwaysOn state:

using Hangfire;
using Toggly.FeatureManagement;
using Toggly.FeatureManagement.HangfireExtensions;

var featureStateService = app.Services.GetRequiredService<IFeatureStateService>();
featureStateService.AddOrUpdateJob<ITestRecurringJob>(
app.Services,
"hourly-job",
"Hourly job", // Stable Hangfire recurring job ID.
job => job.RunAsync(),
Cron.Hourly());

Register this once during application startup, not inside a request. Turning the flag off removes future recurring scheduling; it does not cancel a job already running. A configured Hangfire server is needed to execute jobs; registering a recurring job alone does not start a worker.

Working example​

Explore the .NET SDK Sample. Its guided sections include the first flag, request identity, Order VIP targeting, filter presets, named variants, Hangfire, health checks, and OpenAPI filtering. The README maps each section to its source files and includes a manual walkthrough.