この投稿は元々rollgate.io/blog/feature-flags-aspnet-coreに公開されました.
すべての.NETチームは最終的に同じ壁にぶつかります:ステージングで機能が準備できているが、プロダクションにプッシュするには一度にすべてのユーザーにスイッチを切り替える必要があります。何かが壊れる場合——誤った仮定、エッジケース、パフォーマンスの回帰——あなたの唯一の回復手段はロールバックと再デプロイです.
機能フラグは、デプロイメントとリリースを分離することでこの問題を解決します。コードをフラグの後ろに配置し、ダッシュボードから誰がそれを見るかを制御し、パイプラインを触ることなく管理します。1%のユーザーから始め、メトリクスを監視し、100%に拡大します。もしどの段階でもエラーが急増した場合、数秒でフラグを無効にします.
クイックスタート:.NET 8での機能フラグ
NuGetからRollgate SDKをインストールします:
dotnet add package Rollgate.SDK
アプリケーション起動時にクライアントを初期化
using Rollgate.SDK;
var client = new RollgateClient(new RollgateConfig
{
ApiKey = Environment.GetEnvironmentVariable("ROLLGATE_API_KEY") ?? "",
});
await client.InitializeAsync();
if (client.IsEnabled("new-checkout", false))
{
Console.WriteLine("New checkout enabled");
}
client.Dispose();
InitializeAsync()の後、IsEnabledの各呼び出しはメモリ内の辞書から読み取る—1桁のマイクロ秒オーバーヘッド.
依存性注入に登録
ASP.NET Coreでは、クライアントをシングルトンとして登録し、さらに小さくIFeatureFlags抽象化によりコントローラーがテスト可能になる
// Program.cs
builder.Services.AddSingleton<RollgateClient>(sp =>
{
var client = new RollgateClient(new RollgateConfig
{
ApiKey = builder.Configuration["Rollgate:ApiKey"] ?? "",
RefreshInterval = TimeSpan.FromSeconds(30),
});
// Tutorial simplicity. In production, prefer IHostedService.
client.InitializeAsync().GetAwaiter().GetResult();
return client;
});
builder.Services.AddSingleton<IFeatureFlags, RollgateFeatureFlags>();
public interface IFeatureFlags
{
bool IsEnabled(string flagKey, bool defaultValue = false);
}
public sealed class RollgateFeatureFlags : IFeatureFlags
{
private readonly RollgateClient _client;
public RollgateFeatureFlags(RollgateClient client) => _client = client;
public bool IsEnabled(string key, bool def = false) => _client.IsEnabled(key, def);
}
ASP.NET Core コントローラーにおける機能フラグ
インジェクトIFeatureFlags、SDKの種類そのものではありません:
[ApiController]
[Route("api/[controller]")]
public class CheckoutController : ControllerBase
{
private readonly IFeatureFlags _flags;
public CheckoutController(IFeatureFlags flags) => _flags = flags;
[HttpPost]
public async Task<IActionResult> CreateOrder([FromBody] OrderRequest request)
{
return _flags.IsEnabled("checkout-v2", false)
? Ok(await ProcessV2Async(request))
: Ok(await ProcessV1Async(request));
}
}
ユーザーを特定する — セッションごとに1回、リクエストごとにしない
RollgateClient.IdentifyAsync HTTPリクエストを発行し、フラグをリフレッシュします。 すべてのリクエストで呼び出さないで — それにより、各エンドポイントごとにネットワークのラウンドトリップが追加され、メモリ内の評価モデルが破壊されます。
適切な場所はユーザーごとに一度だけ実行されるアクションフィルタであり、その後ショートサーキットします:
public class FeatureFlagIdentityFilter : IAsyncActionFilter
{
private readonly RollgateClient _client;
private static readonly HashSet<string> _identified = new();
private static readonly SemaphoreSlim _gate = new(1, 1);
public FeatureFlagIdentityFilter(RollgateClient client) => _client = client;
public async Task OnActionExecutionAsync(ActionExecutingContext ctx, ActionExecutionDelegate next)
{
var userId = ctx.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
if (!string.IsNullOrEmpty(userId) && !_identified.Contains(userId))
{
await _gate.WaitAsync();
try
{
if (!_identified.Contains(userId))
{
await _client.IdentifyAsync(new UserContext { Id = userId });
_identified.Add(userId);
}
}
finally { _gate.Release(); }
}
await next();
}
}
本番環境用クリーンナー:ログイン時にIdentifyAsyncを一度だけ呼び出し、ログアウトまで再度は呼び出さない。
最小APIにおける機能フラグ
app.MapPost("/api/search", async (SearchRequest req, IFeatureFlags flags) =>
{
return flags.IsEnabled("semantic-search", false)
? Results.Ok(await RunSemanticSearchAsync(req.Query))
: Results.Ok(await RunKeywordSearchAsync(req.Query));
});
エンドポイントフィルタで全ルートをゲートし、リクエストサービスからIFeatureFlagsを解決します:
public static class FeatureFlagEndpointExtensions
{
public static TBuilder RequireFeature<TBuilder>(this TBuilder builder, string flagKey)
where TBuilder : IEndpointConventionBuilder
{
return builder.AddEndpointFilter(async (context, next) =>
{
var flags = context.HttpContext.RequestServices.GetRequiredService<IFeatureFlags>();
if (!flags.IsEnabled(flagKey, false)) return Results.NotFound();
return await next(context);
});
}
}
app.MapGet("/api/v2/analytics", GetAnalyticsV2Handler)
.RequireFeature("analytics-v2")
.RequireAuthorization();
Blazor Serverの機能フラグ
@page "/checkout"
@inject IFeatureFlags Flags
@inject AuthenticationStateProvider AuthStateProvider
@if (_showNewCheckout) { <NewCheckoutFlow /> } else { <LegacyCheckoutFlow /> }
@code {
private bool _showNewCheckout;
protected override void OnInitialized()
{
// Runs once per circuit, not per render.
_showNewCheckout = Flags.IsEnabled("checkout-v2", false);
}
}
Blazor WebAssemblyの場合、Program.csの前にサーバーからフラグを取得しますRunAsync():
var host = builder.Build();
await host.Services.GetRequiredService<FlagService>().LoadAsync();
await host.RunAsync();
C言語での機能フラグのテスト
コントローラーがIFeatureFlagsに依存するため、モッキングフレームワークは不要です:
public class FakeFeatureFlags : IFeatureFlags
{
private readonly Dictionary<string, bool> _flags;
public FakeFeatureFlags(Dictionary<string, bool>? f = null) => _flags = f ?? new();
public bool IsEnabled(string key, bool def = false)
=> _flags.TryGetValue(key, out var v) ? v : def;
}
public class CheckoutControllerTests
{
[Fact]
public async Task Returns_V2_When_Flag_Enabled()
{
var flags = new FakeFeatureFlags(new() { ["checkout-v2"] = true });
var controller = new CheckoutController(flags);
var result = await controller.CreateOrder(new OrderRequest { Amount = 99 });
// assert v2 path
}
}
常に両方のフラグ状態をテストします。
様々なロールアウトとユーザー対象
ユーザーアトリビュートを識別する際(セッションごとに1回)に渡してください:
await _client.IdentifyAsync(new UserContext
{
Id = userId,
Email = userEmail,
Attributes = new Dictionary<string, object?>
{
["plan"] = user.SubscriptionPlan,
["country"] = user.Country,
}
});
ダッシュボードでパーセンテージロールアウトとアトリビュートターゲティングを設定 — SDKはすべてのルールをローカルで評価し、評価ごとにAPI呼び出しは不要です。
FAQ
2026年の.NETの機能フラグのアプローチは何ですか?
- 実行時変更なしのシンプルなトグル→
Microsoft.FeatureManagement - CNCFベンダーニュートラルSDK →
OpenFeature .NET - ダッシュボード+ターゲティング+段階的なロールアウト → マネージドサービス(Rollgate、LaunchDarklyなど)
.NETバックグラウンドサービスと互換性がありますか?
はい。RollgateClientをシングルトンとして登録し、BackgroundServiceに注入し、IsEnabledを使用してExecuteAsyncで使用します。
起動時にInitializeAsyncが失敗した場合どうしますか?
キャッシュが存在しない場合、例外が発生します。デフォルトの設定で処理を続けるか、エラーを発生させる(通常はエラーを早めに検出する方が安全です)。
詳細なバージョン(サーキットブレーカー設定、キルスイッチのためのSSEストリーミング、Blazor WebAssemblyパターンを含む)については、rollgate.io/blog/feature-flags-aspnet-coreを参照してください。
無料のRollgateアカウントを作成するには、https://app.rollgate.io/registerを利用してください。 — クレジットカード不要。











