Skip to main content

Controllers and Views

Learn how to use feature flags in MVC controllers, actions, and Razor views.

Controllers & Actions​

Entire controllers, or individual actions can be annotated with the FeatureGate attribute. If the feature is off, they can't execute

[FeatureGate(FeatureFlags.Users)]
[Route("users")]
[Controller]
public class UsersController : Controller
{
...
}

Feature Usage in Controllers​

Stats are collected automatically when a feature is evaluated, but using is different than being available. To mark a controller or controller method to count as active use of a feature (for usage reporting) just add the FeatureUsage attribute

[FeatureGate(FeatureFlags.Users)]
[FeatureUsage(FeatureFlags.Users)]
[Route("users")]
[Controller]
public class UsersController : Controller
{
...
}
warning

The FeatureUsage attribute needs to be declared after the FeatureGate attribute, otherwise, usage will be counted even if the action isn't allowed by the FeatureGate flag, resulting in incorrect reporting

Views​

Import feature flag helpers globally​

In your _ViewImports.cshtml add the following line

@addTagHelper *, Toggly.FeatureManagement.Web
@removeTagHelper Microsoft.FeatureManagement.Mvc.TagHelpers.FeatureTagHelper, Microsoft.FeatureManagement.AspNetCore

Toggly's helper supports name/names, requirement, negate, and an entity context. Remove Microsoft's overlapping <feature> helper so it cannot evaluate the same element without the entity. See Entity context for Order examples.

Anywhere in your views you can now surround the parts of the page that make up the feature

<feature name="FeatureX">
<p>This can only be seen if 'FeatureX' is enabled.</p>
</feature>

Show content when a feature is off with negate:

<feature name="FeatureX">
<p>New experience</p>
</feature>
<feature name="FeatureX" negate="true">
<p>Legacy experience</p>
</feature>

or add display the contents conditionally if Any or All the referenced features are enabled

<feature name="ShoppingCart,Checkout,Donation" requirement="Any">
<div>checkout logic</div>
</feature>
<feature name="ShoppingCart,Checkout,Donation" requirement="Any" negate="true">
<div>upgrade prompt</div>
</feature>
info

It's good practice to create a static class or strings or an enum for your features collection to avoid typos. Feature flags in C# work with both strings and enums

Named variants​

A Boolean flag answers whether a feature is enabled; a named variant chooses which configured experience to show. Toggly's Razor helper has no variant attribute. Resolve the native variant with IVariantFeatureManager, then use an ordinary Razor conditional:

@using Microsoft.FeatureManagement
@using Microsoft.FeatureManagement.FeatureFilters
@inject IVariantFeatureManager Variants
@inject ITargetingContextAccessor Targeting
@{
// Reuse the same authenticated request identity and groups as Boolean targeting.
var targeting = await Targeting.GetContextAsync();
var variant = await Variants.GetVariantAsync("new-dashboard", targeting);
}
@if (variant?.Name == "B")
{
<p>Dashboard B</p>
}
else
{
<p>Default dashboard</p>
}

Configure the named variants and their allocation in Toggly first. Handle a missing variant and the configured default explicitly. If rendering also requires Boolean enablement, wrap this composition in a feature gate; a variant's name alone is not an authorization check.

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.