Configuration
Learn about configuration options and advanced settings for the .NET SDK.
Disabled Action Handling
When an MVC controller or action is blocked because none of the features it specifies are enabled, a registered IDisabledFeaturesHandler will be invoked. By default, a minimalistic handler is registered which returns HTTP 404. This can be overridden using the IFeatureManagementBuilder when registering feature flags.
public interface IDisabledFeaturesHandler
{
Task HandleDisabledFeature(IEnumerable<string> features, ActionExecutingContext context);
}
Example implementation
public class FeatureNotEnabledHandler : IDisabledFeaturesHandler
{
public Task HandleDisabledFeatures(IEnumerable<string> features, ActionExecutingContext context)
{
var result = new ViewResult()
{
ViewName = "Views/Shared/FeatureNotEnabled.cshtml",
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
};
result.ViewData["FeatureName"] = string.Join(", ", features);
context.Result = result;
return Task.CompletedTask;
}
}
Then register as singleton in startup.cs
services.AddSingleton<IDisabledFeaturesHandler, FeatureNotEnabledHandler>();
Undefined Features In Development
To enable a more streamlined developer experience, we can treat undefined features as Always On, to avoid having to go into Toggly and define the feature.
Simply add UndefinedEnabledOnDevelopment to AddTogglyWeb.
builder.Services.AddTogglyWeb(options =>
{
options.AppKey = builder.Configuration["Toggly:AppKey"]!;
options.Environment = builder.Configuration["Toggly:Environment"]!;
options.UndefinedEnabledOnDevelopment = true;
});
Don't worry, we auto-detect new flags being checked, and show you any undefined ones on the Feature Definitions page at the bottom.
This works with app.Environment.IsDevelopment() to only affect development. For all other environments, you'll still need to define the feature
Deployments and Version
We try to detect when you've released a new version of your app using the AppVersion option specified in AddTogglyWeb. If not specified, we try to use the version of the entry assembly to your app
To specify a version manually, add the current version to AddTogglyWeb
services.AddTogglyWeb(options =>
{
options.AppKey = Configuration["Toggly:AppKey"]!;
options.Environment = Configuration["Toggly:Environment"]!;
options.AppVersion = "7.10.1";
});
If not specified, we default to Assembly.GetEntryAssembly()?.GetName().Version
To disable version tracking, set AppVersion to String.Empty
Signed Definitions (recommended for production)
When feature flags gate security-sensitive behavior, enable cryptographic verification:
builder.Services.AddTogglyWeb(options =>
{
options.AppKey = builder.Configuration["Toggly:AppKey"]!;
options.Environment = builder.Configuration["Toggly:Environment"]!;
options.UseSignedDefinitions = true;
options.AllowedKeyIds = new HashSet<string> { "yourKeyIdES256" }; // optional pin
// options.JwksCacheDuration = TimeSpan.FromDays(30); // default
});
BaseUrl and DefinitionsBaseUrl are trusted configuration. Only override
them for self-hosted or private deployments you control. A malicious
DefinitionsBaseUrl can redirect definitions/JWKS fetches.
Hangfire jobs registered via AddOrUpdateJob follow flag state — pair them with
UseSignedDefinitions in production so job enablement cannot be flipped by an
unsigned definitions channel.
Missing Feature Filters
By default the SDK fails closed: evaluating a flag that references an unregistered filter throws. To ignore missing filters (not recommended for security-sensitive apps):
services.Configure<FeatureManagementOptions>(options =>
{
options.IgnoreMissingFeatureFilters = true;
});
Logging
Set the Toggly.FeatureManagement category to Debug when diagnosing fetch or
signature issues. Remote HTTP response bodies are logged only at Debug:
builder.Logging.AddFilter("Toggly.FeatureManagement", LogLevel.Debug);
Debugging Endpoint
In case you want to see the current definitions of the flags or recorded metrics, usage stats, you can use the IMetricsDebug, IUsageStatsDebug or IFeatureProviderDebug.
App keys in debug payloads are masked (last 6 characters only).
app.MapGet("/feature-debug", async ctx => await ctx.Response.WriteAsJsonAsync(new
{
Metrics = ctx.RequestServices.GetRequiredService<IMetricsDebug>().GetDebugInfo(),
UsageStats = ctx.RequestServices.GetRequiredService<IUsageStatsDebug>().GetDebugInfo(),
FeatureProvider = ctx.RequestServices.GetRequiredService<IFeatureProviderDebug>().GetDebugInfo(),
}));