.NET 機能管理

Microsoft.FeatureManagement
Microsoft.FeatureManagement.AspNetCore

Microsoft.FeatureManagement
Microsoft.FeatureManagement.AspNetCore
Microsoft.FeatureManagement.Telemetry.ApplicationInsights

.NET 機能管理ライブラリでは、機能フラグに基づいてアプリケーション機能を開発および公開する方法が提供されます。 新しい機能が開発されると、多くのアプリケーションでは、その機能を有効にすべきタイミングや、有効にすべきタイミングなど、特別な要件が発生します。 このライブラリでは、これらの関係を定義する方法が提供され、これらの機能を公開できるようにするために、一般的な .NET コード パターンに統合されています。

機能フラグでは、.NET および ASP.NET Core アプリケーションで機能を動的にオンまたはオフにする方法が提供されます。 開発者は、条件付きステートメントのように簡単なユース ケースから、ルートや MVC フィルターを条件付きで追加するような高度なシナリオまで、機能フラグを使用できます。 機能フラグは、.NET Core 構成システム上に構築されます。 任意の .NET Core 構成プロバイダーは、機能フラグのバックボーンとして機能させることができます。

.NET 機能管理ライブラリを使用するメリットを次に示します。

  • 機能管理のための一般的な規則

  • 参入障壁の低さ

    • IConfiguration 上への構築
    • JSON ファイル機能フラグ設定のサポート
  • 機能フラグの有効期間の管理

    • 構成値はリアルタイムで変更できます。機能フラグは要求全体で整合性があります
  • シンプルなシナリオから複雑なシナリオまで対応

    • 宣言型構成ファイルを通じた機能のオン/オフの切り替え
    • サーバーへの呼び出しに基づいて機能の状態を動的に評価
  • ASP.NET Core と MVC フレームワーク用の API 拡張

    • ルーティング
    • フィルター
    • Action 属性

    .NET 機能管理ライブラリはオープン ソースです。 詳細については、GitHub リポジトリを参照してください。

機能フラグ

機能フラグは、名前と、機能をオンにするための機能フィルターの一覧の 2 つで構成されます。

機能フィルター

機能フィルターは、機能を有効にする必要があるシナリオを定義します。 機能がオンかオフか評価される場合に、機能フィルターの一覧は、いずれかのフィルターがその機能を有効にする必要があると決定するまで走査されます。 この時点で、その機能は有効であるとみなされ、機能フィルターの走査は停止します。 どの機能フィルターも機能を有効にすることを示していない場合は、無効とみなされます。

例として、Microsoft Edge ブラウザーの機能フィルターを設計できます。 この機能フィルターは、HTTP 要求が Microsoft Edge から派生したものである限り、そのフィルターが接続されているすべての機能をアクティブにします。

機能フラグの構成

.NET Core 構成システムは、機能フラグの状態を決定するために使用されます。 このシステムの基盤は IConfiguration です。 IConfiguration の任意のプロバイダーは、機能フラグ ライブラリ用の機能状態プロバイダーとして使用できます。 このシステムは、appsettings.json から Azure App Configuration などまでの範囲のシナリオを有効にします。

機能フラグの宣言

機能管理ライブラリは、.NET Core の IConfiguration システムのプロバイダーであるため、機能フラグ ソースとして appsettings.json をサポートしています。 以下は、json ファイルで機能フラグを設定するために使用される形式の例です。

{
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },

    // Define feature flags in a json file
    "FeatureManagement": {
        "FeatureT": {
            "EnabledFor": [
                {
                    "Name": "AlwaysOn"
                }
            ]
        },
        "FeatureU": {
            "EnabledFor": []
        },
        "FeatureV": {
            "EnabledFor": [
                {
                    "Name": "TimeWindow",
                    "Parameters": {
                        "Start": "Wed, 01 May 2019 13:59:59 GMT",
                        "End": "Mon, 01 Jul 2019 00:00:00 GMT"
                    }
                }
            ]
        }
    }
}

JSON ドキュメントの FeatureManagement セクションが機能フラグ設定を読み込むための慣例によって使用されます。 上記のセクションでは、3 つの異なる機能が見られます。 機能は EnabledFor プロパティを使用して機能フィルターを定義します。 FeatureT 用の機能フィルターには、AlwaysOn があります。 この機能フィルターは組み込みであり、指定されると常にその機能が有効になります。 AlwaysOn 機能フィルターでは構成が必要ないため、Name プロパティしかありません。 FeatureU はその EnabledFor プロパティにフィルターがないため、有効になることはありません。 この機能が有効であることに依存する機能は、機能フィルターが空のままである限りアクセスできません。 ただし、機能を有効にする機能フィルターが追加されると、すぐに機能を開始します。 FeatureV は、TimeWindow という名前の機能フィルターを指定します。 これは構成可能な機能フィルターの例です。 フィルターに Parameters プロパティがある例で確認できます。 これは、フィルターの構成に使用されます。 この場合、機能がアクティブになる開始時間と終了時間が構成されます。

FeatureManagement セクションの詳細なスキーマはこちらで見つけることができます。

詳細設定: 機能フラグ名でのコロン ':' の使用は禁止されています。

宣言のオン/オフ

次のスニペットは、オン/オフ機能に使用できる機能を定義する別の方法を示しています。

{
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },

    // Define feature flags in config file
    "FeatureManagement": {
        "FeatureT": true, // On feature
        "FeatureX": false // Off feature
    }
}

RequirementType

機能フラグの RequirementType プロパティは、フィルターが機能の状態を評価する場合に Any または All ロジックを使用する必要があるかどうかを決定するために使用されます。 RequirementType を指定しない場合の既定値は Any です。

  • Any は、1 つのフィルターだけが true と評価されると、その機能が有効になることを意味します。
  • All は、機能を有効にするために、すべてのフィルターが true と評価される必要があることを意味します。

AllRequirementType は走査を変更します。 まず、フィルターがない場合、この機能は無効になります。 次に、フィルターのいずれかがその機能を無効にする必要があると判断するまで、機能フィルターが走査されます。 どのフィルターも機能を無効にすることを示していない場合は、有効とみなされます。

"FeatureW": {
    "RequirementType": "All",
    "EnabledFor": [
        {
            "Name": "TimeWindow",
            "Parameters": {
                "Start": "Mon, 01 May 2023 13:59:59 GMT",
                "End": "Sat, 01 Jul 2023 00:00:00 GMT"
            }
        },
        {
            "Name": "Percentage",
            "Parameters": {
                "Value": "50"
            }
        }
    ]
}

上記の例では、FeatureWAllRequirementType を指定します。つまり、その機能を有効にするには、すべてのフィルターが true と評価される必要があります。 この場合、指定された時間枠に 50% のユーザーに対してこの機能が有効になります。

Microsoft 機能管理スキーマ

機能管理ライブラリは、機能フラグを宣言するための Microsoft Feature Management schema の使用もサポートしています。 このスキーマは言語を選ばず、すべての Microsoft 機能管理ライブラリでサポートされています。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "FeatureT",
                "enabled": true,
                "conditions": {
                    "client_filters": [
                        {  
                            "name": "Microsoft.TimeWindow",
                            "parameters": {
                                "Start": "Mon, 01 May 2023 13:59:59 GMT",
                                "End": "Sat, 01 Jul 2023 00:00:00 GMT"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

Note

構成内で feature_management セクションが見つかると、FeatureManagement セクションは無視されます。

機能管理ライブラリは、.NET Core の IConfiguration システムのプロバイダーであるため、機能フラグ ソースとして appsettings.json をサポートしています。 機能フラグは Microsoft Feature Management schema を使用して宣言されます。 このスキーマは言語を選ばず、すべての Microsoft 機能管理ライブラリでサポートされています。

以下は、json ファイルで宣言する機能フラグの例です。

{
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },

    // Define feature flags in a json file
    "feature_management": {
        "feature_flags": [
            {
                "id": "FeatureT",
                "enabled": false
            },
            {
                "id": "FeatureU",
                "enabled": true,
                "conditions": {}
            },
            {
                "id": "FeatureV",
                "enabled": true,
                "conditions": {
                    "client_filters": [
                        {  
                            "name": "Microsoft.TimeWindow",
                            "parameters": {
                                "Start": "Mon, 01 May 2023 13:59:59 GMT",
                                "End": "Sat, 01 July 2023 00:00:00 GMT"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

JSON ドキュメントの feature_management セクションが機能フラグ設定を読み込むための慣例によって使用されます。 機能フラグ オブジェクトは、feature_management セクションの feature_flags 配列に一覧表示されている必要があります。 上記のセクションでは、3 つの異なる機能が提供されていることを確認できます。 機能フラグには id および enabled プロパティがあります。 id は、機能フラグを特定および参照するために使用される名前です。 enabled プロパティは、機能フラグの有効な状態を指定します。 enabled が false である場合、機能は [オフ] です。 enabled が true である場合は、機能の状態は conditions に依存します。 conditions がない場合は [オン] になります。 conditions があり、それが満たされている場合は、機能は [オン] です。 conditions があり、それが満たされていない場合は、機能は [オフ] です。 conditions プロパティは、機能を動的に有効にするための条件を宣言します。 機能は client_filters 配列で機能フィルターを定義します。 FeatureV は、Microsoft.TimeWindow という名前の機能フィルターを指定します。 これは構成可能な機能フィルターの例です。 フィルターに Parameters プロパティがある例で確認できます。 これは、フィルターの構成に使用されます。 この場合、機能がアクティブになる開始時間と終了時間が構成されます。

詳細設定: 機能フラグ名でのコロン ':' の使用は禁止されています。

RequirementType

conditionsrequirement_type プロパティは、フィルターが機能の状態を評価する場合に Any または All ロジックを使用する必要があるかどうかを決定するために使用されます。 requirement_type を指定しない場合の既定値は Any です。

  • Any は、1 つのフィルターだけが true と評価されると、その機能が有効になることを意味します。
  • All は、機能を有効にするために、すべてのフィルターが true と評価される必要があることを意味します。

Allrequirement_type は走査を変更します。 まず、フィルターがない場合、この機能は無効になります。 次に、フィルターがある場合は、フィルターのいずれかがその機能を無効にする必要があると判断するまで、機能フィルターが走査されます。 どのフィルターも機能を無効にすることを示していない場合は、有効とみなされます。

{
    "id": "FeatureW",
    "enabled": true,
    "conditions": {
        "requirement_type": "All",
        "client_filters": [
            {
                "name": "Microsoft.TimeWindow",
                "parameters": {
                    "Start": "Mon, 01 May 2023 13:59:59 GMT",
                    "End": "Sat, 01 Jul 2023 00:00:00 GMT"
                }
            },
            {
                "name": "Microsoft.Percentage",
                "parameters": {
                    "Value": "50"
                }
            }
        ]
    }
}

上記の例では、FeatureWAllrequirement_type を指定します。つまり、その機能を有効にするには、すべてのフィルターが true と評価される必要があります。 この場合、指定された時間枠に 50% のユーザーに対してこの機能が有効になります。

.NET 機能管理スキーマ

以前のバージョンでは、機能管理ライブラリのプライマリ スキーマは .NET feature management schema でした。 v4.0.0 以降は、バリアントとテレメトリを含む新しい機能は、.NET 機能管理スキーマではサポートされません。

Note

feature_managementFeatureManagement の両セクションに存在する機能フラグ宣言がある場合は、feature_management セクションのものが採用されます。

従量課金

機能管理の基本フォームは、機能フラグが有効かどうかを確認し、その結果に基づいてアクションを実行することです。 これは IFeatureManagerIsEnabledAsync メソッドを通じて行われます。

…
IFeatureManager featureManager;
…
if (await featureManager.IsEnabledAsync("FeatureX"))
{
    // Do something
}

サービス登録

機能管理は、.NET Core の依存関係の挿入に依存します。 機能管理サービスは、標準の規則を使用して登録できます。

using Microsoft.FeatureManagement;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddFeatureManagement();
    }
}

機能マネージャーは、既定では .NET Core 構成データの "FeatureManagement" セクションから機能フラグの構成を取得します。 "FeatureManagement" セクションが存在しない場合、構成は空とみなされます。

Note

AddFeatureManagement にセクションを渡すことで、機能フラグ構成を別の構成セクションから取得するように指定することもできます。 次の例では、代わりに "MyFeatureFlags" という別のセクションから読み取るように機能マネージャーに指示しています。

services.AddFeatureManagement(configuration.GetSection("MyFeatureFlags"));

依存関係の挿入

機能管理ライブラリを MVC で使用する場合、IFeatureManager は依存関係の挿入を通じて取得できます。

public class HomeController : Controller
{
    private readonly IFeatureManager _featureManager;
    
    public HomeController(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }
}

範囲指定された機能管理サービス

AddFeatureManagement メソッドは、アプリケーション内でシングルトンとして機能管理サービスを追加しますが、代わりに、範囲指定されたサービスとして機能管理サービスを追加する必要があるシナリオもあります。 たとえば、ユーザーは、コンテキスト情報のために範囲指定されたサービスを消費する機能フィルターを使用する場合があります。 この場合、代わりに AddScopedFeatureManagement メソッドを使用する必要があります。 これにより、機能フィルターを含む機能管理サービスが範囲指定されたサービスとして追加されます。

services.AddScopedFeatureManagement();

ASP.NET Core 統合

機能管理ライブラリは、ASP.NET Core と MVC で機能を提供し、Web アプリケーションで一般的な機能フラグ シナリオを有効にします。 これらの機能は Microsoft.FeatureManagement.AspNetCore NuGet パッケージを参照することで使用できます。

コントローラーとアクション

MVC コントローラーとアクションを実行するためには、指定した機能 (あるいは任意の機能リストのいずれか) を有効にする必要があります。 これは Microsoft.FeatureManagement.Mvc 名前空間にある FeatureGateAttribute を使用することで実行できます。

[FeatureGate("FeatureX")]
public class HomeController : Controller
{
    …
}

上記の HomeController は "FeatureX "によって限定されます。 "FeatureX" は HomeController に含まれるアクションが実行される前に有効になっている必要があります。

[FeatureGate("FeatureX")]
public IActionResult Index()
{
    return View();
}

上記の Index MVC アクションは、実行する前に "FeatureX" が有効になっている必要があります。

無効なアクションの処理

指定した機能が有効でないために MVC コントローラーやアクションがブロックされると、登録された IDisabledFeaturesHandler が呼び出されます。 既定では、HTTP 404 を返す最小限のハンドラーが登録されています。 これは、機能フラグを登録する場合に IFeatureManagementBuilder を使用して上書きできます。

public interface IDisabledFeaturesHandler
{
    Task HandleDisabledFeature(IEnumerable<string> features, ActionExecutingContext context);
}

表示

MVC ビューでは、<feature> タグを使用して、機能フラグが有効か無効かに基づいてコンテンツを条件付きでレンダリングできます。

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

また、ある機能や機能のセットが無効になっている場合に、タグ ヘルパーの評価を無効にしてコンテンツを表示することもできます。 以下の例で negate="true" を設定することで、FeatureX が無効な場合にのみコンテンツがレンダリングされます。

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

<feature> タグは、name 属性でカンマ区切りの機能の一覧を指定することで、複数の機能を参照できます。

<feature name="FeatureX,FeatureY">
  <p>This can only be seen if 'FeatureX' and 'FeatureY' are enabled.</p>
</feature>

既定では、機能タグがレンダリングされるには、一覧表示されたすべての機能が有効になっている必要があります。 この動作は、以下の例のように requirement 属性を追加することでオーバーライドできます。

<feature name="FeatureX,FeatureY" requirement="Any">
  <p>This can only be seen if either 'FeatureX' or 'FeatureY' or both are enabled.</p>
</feature>

MVC ビューでは、<feature> タグを使用して、機能フラグが有効か無効か、または機能の特定のバリアントが割り当てられているかに基づいてコンテンツを条件付きでレンダリングできます。 詳しくは、「バリアント」セクションをご覧ください。

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

また、ある機能や機能のセットが無効になっている場合に、タグ ヘルパーの評価を無効にしてコンテンツを表示することもできます。 以下の例で negate="true" を設定することで、FeatureX が無効な場合にのみコンテンツがレンダリングされます。

<feature negate="true" name="FeatureX">
  <p>This can only be seen if 'FeatureX' is disabled.</p>
</feature>
<feature negate="true" name="FeatureX" variant="Alpha">
  <p>This can only be seen if variant 'Alpha' of 'FeatureX' isn't assigned.</p>
</feature>

<feature> タグは、name/variant 属性でカンマ区切りの機能またはバリアントの一覧を指定することで、複数の機能またはバリアントを参照できます。

<feature name="FeatureX,FeatureY">
  <p>This can only be seen if 'FeatureX' and 'FeatureY' are enabled.</p>
</feature>
<feature name="FeatureX" variant="Alpha,Beta">
  <p>This can only be seen if variant 'Alpha' or 'Beta' of 'FeatureX' is assigned.</p>
</feature>

Note

variant を指定した場合、1 つの機能のみを指定する必要があります。

既定では、機能タグがレンダリングされるには、一覧表示されたすべての機能が有効になっている必要があります。 この動作は、以下の例のように requirement 属性を追加することでオーバーライドできます。

Note

Andrequirementvariant と一緒に使用されると、複数のバリアントを割り当てできないというエラーがスローされます。

<feature name="FeatureX,FeatureY" requirement="Any">
  <p>This can only be seen if either 'FeatureX' or 'FeatureY' or both are enabled.</p>
</feature>

<feature> タグを使用するにはタグ ヘルパーが必要です。 これは、ViewImports.cshtml ファイルに機能管理タグ ヘルパーを追加することで実行できます。

@addTagHelper *, Microsoft.FeatureManagement.AspNetCore

MVC フィルター

MVC アクション フィルターは、機能の状態に基づいて条件付きで実行するように設定できます。 これは、機能を意識した方法で MVC フィルターを登録することによって行われます。 機能管理パイプラインは、IAsyncActionFilter を実装する非同期 MVC Action フィルターをサポートしています。

services.AddMvc(o => 
{
    o.Filters.AddForFeature<SomeMvcFilter>("FeatureX");
});

上記のコードは、SomeMvcFilter という名前の MVC フィルターを追加します。 このフィルターは、 "FeatureX" が有効になっている場合のみ、MVC パイプライン内でトリガーされます。

Razor ページ

MVC Razor ページを実行するためには、指定した機能 (あるいは任意の機能リストのいずれか) を有効にする必要があります。 これは Microsoft.FeatureManagement.Mvc 名前空間にある FeatureGateAttribute を使用することで実行できます。

[FeatureGate("FeatureX")]
public class IndexModel : PageModel
{
    public void OnGet()
    {
    }
}

上記のコードでは、"FeatureX" を有効にする必要があるため Razor ページを設定しています。 この機能が有効でない場合、ページは HTTP 404 (NotFound) の結果を生成します。

Razor ページで使用する場合、FeatureGateAttribute はページ ハンドラーの種類に配置する必要があります。 個別のハンドラー メソッドに配置することはできません。

アプリケーションの構築

機能管理ライブラリは、機能の状態に基づいて条件付きで実行されるアプリケーション分岐やミドルウェアを追加するために使用できます。

app.UseMiddlewareForFeature<ThirdPartyMiddleware>("FeatureX");

上記の呼び出しで、アプリケーションは、"FeatureX" 機能が有効な場合にのみ要求パイプラインに現れるミドルウェア コンポーネントを追加します。 実行中に機能を有効または無効にすると、ミドルウェア パイプラインを動的に変更できます。

以下は、機能に基づいてアプリケーション全体を分岐させる、より汎用的な機能を構築します。

app.UseForFeature(featureName, appBuilder => 
{
    appBuilder.UseMiddleware<T>();
});

機能フィルターの実装

機能フィルターを作成すると、定義した条件に基づいて機能を有効にする方法を得られます。 機能フィルターを実装するには、IFeatureFilter インターフェイスを実装する必要があります。 IFeatureFilter には EvaluateAsync という名前の単一のメソッドがあります。 機能が機能フィルターに対して有効であることを指定すると、EvaluateAsync メソッドが呼び出されます。 EvaluateAsynctrue を返す場合は、機能が有効になっていることを意味します。

次のスニペットは、カスタマイズされた機能フィルター MyCriteriaFilter を追加する方法を示しています。

services.AddFeatureManagement()
        .AddFeatureFilter<MyCriteriaFilter>();

機能フィルターは AddFeatureManagement から返された IFeatureManagementBuilderAddFeatureFilter<T> を呼び出すことで登録されます。 これらの機能フィルターは、機能フラグを追加するために使用されたサービス コレクション内に存在するサービスにアクセスできます。 依存関係の挿入は、これらのサービスを取得するために使用できます。

Note

フィルターが機能フラグ設定 (appsettings.json など) で参照される場合、型名の Filter 部分は省略する必要があります。 詳細については、「Filter Alias Attribute」のセクションを参照してください。

パラメーター化された機能フィルター

一部の機能フィルターでは、機能をオンにするかどうかを決定するためのパラメーターが必要です。 たとえば、ブラウザー機能フィルターでは、特定のブラウザー セットの機能を有効にすることができます。 Edge およびChrome ブラウザーでは機能を有効にできますが、Firefox ではできません。 これを行うために、パラメーターを予測する機能フィルターを設計できます。 これらのパラメーターは機能構成で指定され、IFeatureFilter.EvaluateAsyncFeatureFilterEvaluationContext パラメーターを介してコードにアクセスできるようになります。

public class FeatureFilterEvaluationContext
{
    /// <summary>
    /// The name of the feature being evaluated.
    /// </summary>
    public string FeatureName { get; set; }

    /// <summary>
    /// The settings provided for the feature filter to use when evaluating whether the feature should be enabled.
    /// </summary>
    public IConfiguration Parameters { get; set; }
}

FeatureFilterEvaluationContext には Parameters という名前のプロパティがあります。 これらのパラメーターは、機能フィルターが機能を有効にする必要があるか評価する方法を決定するために使用できる生の構成を表します。 ブラウザー機能フィルターをもう一度例として使用するために、フィルターは機能用に指定される許可されたブラウザーのセットを抽出し、要求がそれらのブラウザーのどれかから送信されているか確認するために Parameters を使用できます。

[FilterAlias("Browser")]
public class BrowserFilter : IFeatureFilter
{
    …

    public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
    {
        BrowserFilterSettings settings = context.Parameters.Get<BrowserFilterSettings>() ?? new BrowserFilterSettings();

        //
        // Here we would use the settings and see if the request was sent from any of BrowserFilterSettings.AllowedBrowsers
    }
}

フィルター Alias 属性

機能フラグ用に機能フィルターが登録されている場合、構成で使用されるエイリアスは、Filter サフィックスがある場合は、それを取り除いた機能フィルターの種類の名前になります。 たとえば、MyCriteriaFilter は構成では MyCriteria と呼ばれます。

"MyFeature": {
    "EnabledFor": [
        {
            "Name": "MyCriteria"
        }
    ]
}

これをオーバーライドするには、FilterAliasAttribute を使用します。 機能フィルターをこの属性で装飾することで、機能フラグ内でこの機能フィルターを参照するために構成で使用する必要がある名前を宣言できます。

欠落した機能フィルター

機能が特定の機能フィルターに対して有効になるように構成されていて、その機能フィルターが登録されていない場合、機能の評価時に例外がスローされます。 例外は、機能管理オプションを使用して無効にすることができます。

services.Configure<FeatureManagementOptions>(options =>
{
    options.IgnoreMissingFeatureFilters = true;
});

HttpContext の使用

機能フィルターは、HTTP 要求のプロパティに基づいて機能を有効にする必要があるか評価できます。 これは HTTP コンテキストを検査することで実行されます。 機能フィルターは、依存関係の挿入を通じて IHttpContextAccessor を取得することで、HTTP コンテキストへの参照を取得できます。

public class BrowserFilter : IFeatureFilter
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public BrowserFilter(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
    }
}

IHttpContextAccessor を使用できるようにするには、起動時に依存関係の挿入コンテナーに追加する必要があります。 次の方法で IServiceCollection に登録できます。

public void ConfigureServices(IServiceCollection services)
{
    …
    services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    …
}

詳細設定: IHttpContextAccessor/HttpContext はサーバー側の Blazor アプリの Razor コンポーネントでは使用しないでください。 Blazor アプリで HTTP コンテキストを渡すために推奨されるアプローチは、データを範囲指定されたサービスにコピーすることです。 Blazor アプリの場合、AddScopedFeatureManagement を使用して機能管理サービスを登録する必要があります。 詳細については、「Scoped Feature Management Services」のセクションを参照してください。

機能評価のためのコンテキストの提供

コンソール アプリケーションには、機能フィルターで機能がオンかオフかを確認するために取得して利用できる HttpContext のような環境コンテキストはありません。 この場合、アプリケーションは、機能フィルターで使用するために、コンテキストを表すオブジェクトを機能管理システムに提供する必要があります。 これは、IFeatureManager.IsEnabledAsync<TContext>(string featureName, TContext appContext) を使用して行います。 機能マネージャーに提供される appContext オブジェクトは、機能の状態を評価するために機能フィルターで使用できます。

MyAppContext context = new MyAppContext
{
    AccountId = current.Id;
}

if (await featureManager.IsEnabledAsync(feature, context))
{
…
}

コンテキスト機能フィルター

コンテキスト機能フィルターは IContextualFeatureFilter<TContext> インターフェイスを実装します。 これらの特殊な機能フィルターはIFeatureManager.IsEnabledAsync<TContext> が呼び出されたときに渡されるコンテキストを活用できます。 IContextualFeatureFilter<TContext>TContext 型パラメーターは、フィルターで処理できるコンテキストの種類を記述します。 これにより、コンテキスト機能フィルターの開発者は、それを利用したいユーザーのために必要な内容を記述できます。 すべての種類はオブジェクトの子孫であるため、IContextualFeatureFilter<object> を実装するフィルターは、提供された任意のコンテキストに対して呼び出すことができます。 より具体的なコンテキスト機能フィルターの例として、構成された有効なアカウントの一覧にアカウントがある場合に有効になる機能を考慮してください。

public interface IAccountContext
{
    string AccountId { get; set; }
}

[FilterAlias("AccountId")]
class AccountIdFilter : IContextualFeatureFilter<IAccountContext>
{
    public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext featureEvaluationContext, IAccountContext accountId)
    {
        //
        // Evaluate if the feature should be on with the help of the provided IAccountContext
    }
}

AccountIdFilter では、機能の状態を評価できるようにするために提供される IAccountContext を実装するオブジェクトが必要であることがわかります。 この機能フィルターを使用する場合、呼び出し元は IAccountContext を実装するオブジェクトで渡されることを確認する必要があります。

Note

1 つの種類を実装できるのは、1 つの機能フィルター インターフェイスのみです。 複数の機能フィルター インターフェイスを実装する機能フィルターを追加しようとすると、ArgumentException が生成されます。

同じエイリアスを使用するコンテキスト フィルターと非コンテキスト フィルターの使用

IFeatureFilterIContextualFeatureFilter のフィルターは同じエイリアスを共有できます。 具体的には、ContextType に適用可能なフィルターが最大 1 つある限り、0 または 1 個の IFeatureFilter と 0 または N 個の IContextualFeatureFilter<ContextType> で共有される 1 つのフィルター エイリアスを持つことができます。

次の文章では、アプリケーションに同じ名前のコンテキスト フィルターと非コンテキスト フィルターが登録されている場合の、フィルターの選択プロセスについて説明します。

FilterA という非コンテキスト フィルターと、2 つのコンテキスト フィルター FilterB と、それぞれ TypeB および TypeC コンテキストを承諾する FilterC があるとします。 3 つのフィルターはすべて同じエイリアス SharedFilterName を共有します。

また、構成で機能フィルター SharedFilterName を使用する機能フラグ MyFeature もあります。

3 つのフィルターがすべて登録されている場合:

  • IsEnabledAsync("MyFeature") を呼び出すと、FilterA が機能フラグを評価するために使用されます。
  • IsEnabledAsync("MyFeature"、コンテキスト) を呼び出すと、コンテキストの種類が TypeB の場合は FilterB が使用されます。 コンテキストの種類が TypeC の場合は FilterC が使用されます。
  • IsEnabledAsync("MyFeature"、コンテキスト) を呼び出すと、コンテキストの種類が TypeF の場合は FilterA が使用されます。

組み込み機能フィルター

Microsoft.FeatureManagement パッケージには、PercentageFilterTimeWindowFilterContextualTargetingFilterTargetingFilter などのいくつかの機能フィルターがあります。 TargetingFilter 以外のすべてのフィルターは、AddFeatureManagement メソッドで機能管理が登録されると自動的に追加されます。 TargetingFilter は、以下の Targeting セクションで詳述する WithTargeting メソッドを使用して追加されます。

組み込み機能フィルターにはそれぞれ独自のパラメーターがあります。 こちらは、機能フィルターの一覧と例です。

Microsoft.Percentage

このフィルターは、設定された割合に基づいて機能を有効にする機能を提供します。

"EnhancedPipeline": {
    "EnabledFor": [
        {
            "Name": "Microsoft.Percentage",
            "Parameters": {
                "Value": 50
            }
        }
    ]
}

Microsoft.TimeWindow

このフィルターは、時間枠に基づいて機能を有効にする機能を提供します。 End のみ指定された場合、その時間までその機能はオンとみなされます。 Start のみ指定された場合、その時点以降のすべての時点で機能はオンとみなされます。

"EnhancedPipeline": {
    "EnabledFor": [
        {
            "Name": "Microsoft.TimeWindow",
            "Parameters": {
                "Start": "Wed, 01 May 2019 13:59:59 GMT",
                "End": "Mon, 01 Jul 2019 00:00:00 GMT"
            }
        }
    ]
}

時間枠は定期的に反復するように構成できます。 これは、トラフィックの少ない時間帯や多い時間帯、あるいは特定の曜日に機能をオンにする必要があるシナリオに役立ちます。 個別の時間枠を反復する時間枠に拡張するには、Recurrence パラメーターで繰り返し規則を指定する必要があります。

Note

Recurrence を有効にするには、StartEnd の両方を指定する必要があります。

"EnhancedPipeline": {
    "EnabledFor": [
        {
            "Name": "Microsoft.TimeWindow",
            "Parameters": {
                "Start": "Fri, 22 Mar 2024 20:00:00 GMT",
                "End": "Sat, 23 Mar 2024 02:00:00 GMT",
                "Recurrence": {
                    "Pattern": {
                        "Type": "Daily",
                        "Interval": 1
                    },
                    "Range": {
                        "Type": "NoEnd"
                    }
                }
            }
        }
    ]
}

Recurrence 設定は、Pattern (時間枠を繰り返す頻度) と Range (繰り返しパターンを繰り返す期間) の 2 つの部分で構成されています。

定期的なパターン

繰り返しパターンには、DailyWeekly の 2 種類があります。 たとえば、"毎日"、"3 日ごと"、"毎週月曜日"、"毎週金曜日以外" などの時間枠を繰り返すことができます。

種類によって、Pattern の特定のフィールドは必須、任意、または無視されます。

  • Daily

    日単位の繰り返しパターンでは、それぞれ発生した日の日数に基づいて時間枠が繰り返されます。

    プロパティ 関連性 説明
    Type 必須 Daily に設定する必要があります。
    間隔 省略可能 それぞれ発生した日の日数で指定します。 既定値は 1 です。
  • Weekly

    週単位の繰り返しパターンでは、それぞれ発生した週の週数に基づいて、時間枠が同じ日または曜日に繰り返されます。

    プロパティ 関連性 説明
    Type 必須 Weekly に設定する必要があります。
    DaysOfWeek 必須 イベントが発生する曜日を指定します。
    間隔 省略可能 それぞれ発生した週の週数で指定します。 既定値は 1 です。
    FirstDayOfWeek 省略可能 どの曜日を週の初日とみなすかを指定します。 既定値は Sunday

    次の例は、隔週の月曜日と火曜日に時間枠を繰り返します。

    "Pattern": {
        "Type": "Weekly",
        "Interval": 2,
        "DaysOfWeek": ["Monday", "Tuesday"]
    }
    

Note

Start は、繰り返しパターンに当てはまる有効な最初の発生である必要があります。 さらに、時間枠の期間は、それが発生する頻度よりも長くすることはできません。 たとえば、毎日 25 時間の時間枠の繰り返しは無効です。

定期実行範囲

使用可能な繰り返しの範囲の種類は、NoEndEndDateNumbered の 3 つがあります。

  • NoEnd

    NoEnd の範囲では、繰り返しが無期限に発生します。

    プロパティ 関連性 説明
    Type 必須 NoEnd に設定する必要があります。
  • EndDate

    EndDate の範囲は、終了日まで該当するパターンに当てはまるすべての日に発生するように時間枠に影響します。

    プロパティ 関連性 説明
    Type 必須 EndDate に設定する必要があります。
    EndDate 必須 パターンの適用を停止する日付と時刻を指定します。 最後の発生日の開始時刻が終了日より前である限り、その発生日の終了時刻はその時間を超えて延長できます。

    次の例では、2024 年 4 月 1 日に最後に発生するまで、毎日時間枠を繰り返します。

    "Start": "Fri, 22 Mar 2024 18:00:00 GMT",
    "End": "Fri, 22 Mar 2024 20:00:00 GMT",
    "Recurrence":{
        "Pattern": {
            "Type": "Daily",
            "Interval": 1
        },
        "Range": {
            "Type": "EndDate",
            "EndDate": "Mon, 1 Apr 2024 20:00:00 GMT"
        }
    }
    
  • Numbered

    Numbered の範囲では、時間枠が (パターンに基づいて) 決まった回数発生します。

    プロパティ 関連性 説明
    Type 必須 Numbered に設定する必要があります。
    NumberOfOccurrences 必須 発生回数を指定します。

    次の例では、月曜日と火曜日に時間枠を繰り返し、4 月 1 日 (月)、4 月 2 日 (火)、4 月 8 日 (月) の 3 回発生します。

    "Start": "Mon, 1 Apr 2024 18:00:00 GMT",
    "End": "Mon, 1 Apr 2024 20:00:00 GMT",
    "Recurrence":{
        "Pattern": {
            "Type": "Weekly",
            "Interval": 1,
            "DaysOfWeek": ["Monday", "Tuesday"]
        },
        "Range": {
            "Type": "Numbered",
            "NumberOfOccurrences": 3
        }
    }
    

繰り返し規則を作成するには、PatternRange の両方を指定する必要があります。 どのパターンの種類でも、どの範囲の種類でも機能します。

詳細: Start プロパティのタイム ゾーン オフセットが繰り返し設定に適用されます。

Microsoft.Targeting

このフィルターは、対象ユーザーに対して機能を有効にする機能を提供します。 対象設定の詳細については、以下の「対象設定」セクションで説明します。 フィルター パラメーターには、ユーザー、グループ、除外ユーザー/グループ、およびその機能にアクセスできるユーザーベースの既定の割合を記述する Audience オブジェクトが含まれます。 Groups セクションに一覧表示されている各グループ オブジェクトは、グループのメンバーの何パーセントがアクセスできるかも指定する必要があります。 ユーザーがExclusion セクションで指定されている場合、そのユーザーが直接指定されている場合、またはそのユーザーが除外されているグループに属している場合に、機能は無効になります。 それ以外の場合、Users セクションでユーザーが直接指定された場合、またはユーザーがいずれかのグループ ロールアウトの割合に含まれる場合、またはユーザーが既定ロールアウトの割合に含まれる場合、そのユーザーの機能が有効になります。

"EnhancedPipeline": {
    "EnabledFor": [
        {
            "Name": "Microsoft.Targeting",
            "Parameters": {
                "Audience": {
                    "Users": [
                        "Jeff",
                        "Alicia"
                    ],
                    "Groups": [
                        {
                            "Name": "Ring0",
                            "RolloutPercentage": 100
                        },
                        {
                            "Name": "Ring1",
                            "RolloutPercentage": 50
                        }
                    ],
                    "DefaultRolloutPercentage": 20,
                    "Exclusion": {
                        "Users": [
                            "Ross"
                        ],
                        "Groups": [
                            "Ring2"
                        ]
                    }
                }
            }
        }
    ]
}

機能フィルター Alias 名前空間

すべての組み込み機能フィルターのエイリアスは Microsoft 機能フィルター名前空間にあります。 これは、同じエイリアスを共有する可能性のある他の機能フィルターとの競合を防ぐためです。 機能フィルターの名前空間のセグメントは、'.' 文字で分割されます。 機能フィルターは、Microsoft.Percentage などの完全修飾されたエイリアス、または Microsoft.PercentagePercentage である場合は最後のセグメントで参照できます。

ターゲティング

対象設定は、開発者が新しい機能をユーザー ベースに段階的にロールアウトできるようにする機能管理戦略です。 この戦略は、対象ユーザーと呼ばれる一連のユーザーを対象設定するという概念に基づいて構築されています。 対象ユーザーは、特定のユーザー、グループ、除外されたユーザー/グループ、およびユーザー ベース全体の指定された割合で構成されます。 対象ユーザーに含まれるグループは、メンバーの合計数に対する割合にさらに分けることができます。

次の手順は、新しい「ベータ」機能の段階的なロールアウトの例を示しています。

  1. 個人ユーザーの Jeff と Alicia にベータ版へのアクセス権が付与されます
  2. もう 1 人のユーザー Mark はオプトインを要求し、オプトインされます。
  3. 「Ring1」ユーザーと呼ばれるグループの 20% がベータ版に含まれています。
  4. ベータ版に含まれる「Ring1」ユーザーの数は、最大 100% 増加します。
  5. ユーザー ベースの 5% がベータに含まれています。
  6. ロールアウト率は最大 100% まで増加し、機能は完全にロールアウトされます。

機能をロールアウトするこの戦略では、これに含まれる Microsoft.Targeting 機能フィルターを通してライブラリに組み込まれています。

Web アプリケーションでの対象設定

対象設定機能フィルターを使用する Web アプリケーションの例は FeatureFlagDemo のプロジェクトの例にあります。

アプリケーションで TargetingFilter の使用を開始するには、他の機能フィルターと同様にアプリケーションのサービス コレクションに追加する必要があります。 他の組み込みフィルターとは異なり、TargetingFilter はアプリケーションのサービス コレクションに追加される別のサービスに依存します。 そのサービスは ITargetingContextAccessor です。

Microsoft.FeatureManagement.AspNetCore には、要求の HttpContext からターゲット設定情報を抽出する ITargetingContextAccessor既定の実装が用意されています。 IFeatureManagementBuilder に対して非ジェネリック WithTargeting オーバーロードを使用してターゲット設定を指定するときに、既定のターゲット設定コンテキスト アクセサーを使用できます。

既定の対象設定コンテキスト アクセサーと TargetingFilter は、IFeatureManagementBuilderWithTargeting を呼び出すことで登録されます。

services.AddFeatureManagement()
        .WithTargeting();

WithTargeting<T> を呼び出して、ITargetingContextAccessorTargetingFilter のカスタマイズされた実装を登録することもできます。 ExampleTargetingContextAccessor と呼ばれる ITargetingContextAccessor を実装した TargetingFilter を使用するために、Web アプリケーションで機能管理を設定する例をこちらに示します。

services.AddFeatureManagement()
        .WithTargeting<ExampleTargetingContextAccessor>();

ITargetingContextAccessor

Web アプリケーションで TargetingFilter を使用するには、ITargetingContextAccessor の実装が必要です。 これは、対象設定評価を行う場合に、現時点でどのユーザーを評価しているかなどのコンテキスト情報が必要になるためです。 この情報は TargetingContext と呼ばれます。 アプリケーションによって、この情報を抽出する場合が異なる場合があります。 アプリケーションが対象設定コンテキストを取得する一般的な例として、要求の HTTP コンテキストやデータベースがあります。

アプリケーションの HTTP コンテキストからターゲット設定コンテキスト情報を抽出する例は、Microsoft.FeatureManagement.AspNetCore パッケージが提供する DefaultHttpTargetingContextAccessor です。 これを使って HttpContext.User からターゲット設定情報を抽出します。 UserId 情報は Identity.Name フィールドから抽出され、Groups 情報は種類 Role の要求から抽出されます。 この実装は、ここで説明されている IHttpContextAccessor の使用に依存しています。

コンソール アプリケーションの対象設定

対象設定フィルターは、機能をオンにする必要があるか評価するために、ターゲット設定コンテキストに依存します。 この対象設定コンテキストには、現時点でどのユーザーが評価されているか、どのグループに属しているかなどの情報が含まれています。 コンソール アプリケーションでは、通常、この情報を対象設定フィルターに流すための環境コンテキストはありません。したがって、FeatureManager.IsEnabledAsync が呼び出される場合に渡す必要があります。 これは ContextualTargetingFilter を使用することでサポートされます。 対象設定コンテキストを機能マネージャーに流す必要があるアプリケーションは、TargetingFilter. の代わりにこれを使用する必要があります。

ContextualTargetingFilterIContextualTargetingFilter<ITargetingContext> であるため、ITargetingContext の実装を IFeatureManager.IsEnabledAsync に渡して、その機能を評価してオンにできるようにする必要があります。

IFeatureManager fm;
…
// userId and groups defined somewhere earlier in application
TargetingContext targetingContext = new TargetingContext
{
   UserId = userId,
   Groups = groups
};

await fm.IsEnabledAsync(featureName, targetingContext);

ContextualTargetingFilter は引き続き機能フィルターのエイリアス Microsoft.Targeting を使用しているため、このフィルターの構成はそのセクションで参照されている内容と一致しています。

コンソール アプリケーションで ContextualTargetingFilter を使用する例は TargetingConsoleApp プロジェクトの例にあります。

対象設定評価オプション

すべての機能に対象設定評価を実行する方法をカスタマイズするオプションが用意されています。 これらのオプションは、機能管理の設定時に構成できます。

services.Configure<TargetingEvaluationOptions>(options =>
{
    options.IgnoreCase = true;
});

対象設定の除外

対象ユーザーを定義する場合、ユーザーやグループを対象ユーザーから除外できます。 これは、ある機能をユーザー グループにロールアウトする場合に、一部のユーザーまたはグループをロールアウトから除外する必要がある場合に役立ちます。 除外は、対象ユーザー Exclusion プロパティにユーザーとグループの一覧を追加することで定義されます。

"Audience": {
    "Users": [
        "Jeff",
        "Alicia"
    ],
    "Groups": [
        {
            "Name": "Ring0",
            "RolloutPercentage": 100
        }
    ],
    "DefaultRolloutPercentage": 0
    "Exclusion": {
        "Users": [
            "Mark"
        ]
    }
}

上記の例では、JeffAlicia という名前のユーザーに対してこの機能が有効になっています。 また、Ring0 という名前のグループのユーザーに対しても有効です。 ただし、ユーザーの名前が Mark である場合、そのユーザーがグループ Ring0 に属しているかに関係なく、機能は無効になります。 除外は対象設定フィルターの残りの部分よりも優先されます。

バリアント

アプリケーションに新しい機能が追加される場合、その機能に複数の異なる設計オプションがある場合があります。 設計を決定するための一般的な解決策は、一種の A/B テストです。これは、ユーザー ベースの異なるセグメントに機能の異なるバージョンを提供し、ユーザー操作に基づいてバージョンを選択するものです。 このライブラリでは、機能のさまざまな構成をバリアントで表現することで、この機能が有効になります。

バリアントは、機能フラグを単なるオン/オフのフラグ以上のものにします。 バリアントは機能フラグの値を表し、文字列、数値、ブール値、あるいは構成オブジェクトである場合もあります。 バリアントを宣言する機能フラグは、それぞれのバリアントをどのような状況で使用する必要があるかを定義する必要があります。この詳細については、「バリアントの割り当て」セクションで扱っています。

public class Variant
{
    /// <summary>
    /// The name of the variant.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// The configuration of the variant.
    /// </summary>
    public IConfigurationSection Configuration { get; set; }
}

バリアントの取得

各機能について、IVariantFeatureManagerGetVariantAsync メソッドを使用してバリアントを取得できます。

…
IVariantFeatureManager featureManager;
…
Variant variant = await featureManager.GetVariantAsync(MyFeatureFlags.FeatureU, CancellationToken.None);

IConfigurationSection variantConfiguration = variant.Configuration;

// Do something with the resulting variant and its configuration

バリアントが取得されると、バリアントの設定はバリアントの Configuration プロパティから IConfigurationSection として直接使用できます。 もう 1 つのオプションは、.NET の構成バインド パターンを使用して、構成をオブジェクトにバインドすることです。

IConfigurationSection variantConfiguration = variant.Configuration;

MyFeatureSettings settings = new MyFeatureSettings();

variantConfiguration.Bind(settings);

返されるバリアントは現在評価されているユーザーに依存し、その情報は TargetingContext のインスタンスから得られます。 このコンテキストは GetVariantAsync を呼び出すときに渡すか、ITargetingContextAccessor の実装が登録されている場合はそこから自動的に取得します。

バリアント機能フラグの宣言

通常の機能フラグと比較して、バリアント機能フラグには variantsallocation の 2 つの追加プロパティがあります。 variants プロパティは、この機能に対して定義されたバリアントを含む配列です。 allocation プロパティは、これらのバリアントを機能に割り当てる方法を定義します。 通常の機能フラグを宣言するのと同様に、バリアント機能フラグも json ファイルで設定できます。 こちらにバリアント機能フラグの例を示します。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyVariantFeatureFlag",
                "enabled": true,
                "allocation": {
                    "default_when_enabled": "Small",
                    "group": [
                        {
                            "variant": "Big",
                            "groups": [
                                "Ring1"
                            ]
                        }
                    ]
                },
                "variants": [
                    { 
                        "name": "Big"
                    },  
                    { 
                        "name": "Small"
                    } 
                ]
            }
        ]
    }
}

バリアントの定義

各バリアントには名前と構成の 2 つのプロパティがあります。 名前は特定のバリアントを指すのに使われ、構成はそのバリアントの値です。 この構成は configuration_value プロパティを使用して設定できます。 configuration_value は、文字列、数値、論理値、構成オブジェクトのいずれかに設定できるインライン構成です。 configuration_value が指定されていない場合は、返されたバリアントの Configuration プロパティは null になります。

variants プロパティの下で、各機能に対して利用可能なすべてのバリアントのリストが定義されます。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyVariantFeatureFlag",
                "variants": [
                    { 
                        "name": "Big", 
                        "configuration_value": {
                            "Size": 500
                        }
                    },  
                    { 
                        "name": "Small", 
                        "configuration_value": {
                            "Size": 300
                        }
                    } 
                ]
            }
        ]
    }
}

バリアントの割り当て

機能のバリアントを割り当てるプロセスは、機能の allocation プロパティによって決定されます。

"allocation": { 
    "default_when_enabled": "Small", 
    "default_when_disabled": "Small",  
    "user": [ 
        { 
            "variant": "Big", 
            "users": [ 
                "Marsha" 
            ] 
        } 
    ], 
    "group": [ 
        { 
            "variant": "Big", 
            "groups": [ 
                "Ring1" 
            ] 
        } 
    ],
    "percentile": [ 
        { 
            "variant": "Big", 
            "from": 0, 
            "to": 10 
        } 
    ], 
    "seed": "13973240" 
},
"variants": [
    { 
        "name": "Big", 
        "configuration_value": "500px"
    },  
    { 
        "name": "Small", 
        "configuration_value": "300px"
    } 
]

機能の allocation 設定には次のプロパティがあります。

プロパティ 説明
default_when_disabled 機能が無効とされている間にバリアントが要求された場合に使用するバリアントを指定します。
default_when_enabled 機能が有効であるとみなされ、他のバリアントがユーザーに割り当てられていない場合に、バリアントが要求されたときに使用するバリアントを指定します。
user バリアントと、そのバリアントを割り当てるユーザーの一覧を指定します。
group バリアントとグループの一覧を指定します。 バリアントは、ユーザーが少なくとも 1 つのグループに属している場合に割り当てられます。
percentile バリアントと、そのバリアントを割り当てるためにユーザーの計算されたパーセンテージの範囲を指定します。
seed percentile に対して計算されたパーセンテージの基になる値。 同じ seed 値が使用されている場合、特定のユーザーに対して計算されたパーセンテージはすべての機能で同じになります。 seed が指定されていない場合は、機能名に基づく既定のシードが作成されます。

上記の例では、機能が有効になっていない場合は、機能マネージャーは default_when_disabled とマークされたバリアントを現在のユーザー (この場合は Small) に割り当てます。

この機能が有効になっている場合は、機能マネージャーは usergrouppercentile の割り当てを順番に確認してバリアントを割り当てます。 この具体的な例では、評価されるユーザーが Marsha という名前で、Ring1 というグループに属する場合、またはユーザーが偶然 0 パーセンタイルと 10 パーセンタイルの間に存在する場合、指定されたバリアントがユーザーに割り当てられます。 この場合、これらはすべて Big バリアントを返します。 これらの割り当てがどれも一致しない場合、default_when_enabled のバリアントが割り当てられ、Small になります。

割り当てのロジックは Microsoft.Targeting 機能フィルターと似ていますが、パラメーターには、ターゲット設定に存在するが割り当てに存在しないものや、その逆があります。 対象設定と割り当ての結果は関係ありません。

Note

機能バリアントを割り当てられるようにするには、ITargetingContextAccessor を登録する必要があります。 これは WithTargeting<T> メソッドを呼び出すことで実行できます。

バリアントを使用する有効な状態のオーバーライド

機能フラグの有効な状態をオーバーライドするためにバリアントを使用できます。 これにより、バリアントが機能フラグの評価を拡張する機会が付与されます。 バリアントのあるフラグに対して IsEnabled を呼び出すと、機能マネージャーは、現在のユーザーに割り当てられているバリアントが結果をオーバーライドするように構成されているかどうかを調べます。 これは省略可能なバリアント プロパティ status_override を使用して行われます。 既定では、このプロパティは None に設定されており、バリアントはフラグが有効か無効であるかに影響しないことを意味します。 status_overrideEnabled に設定すると、バリアントが選択されたときにフラグをオーバーライドして有効にすることができます。 status_overrideDisabled に設定すると逆の機能が提供され、バリアントが選択されたときにフラグが無効になります。 enabled 状態が false の機能はオーバーライドできません。

バイナリのバリアントで機能フラグを使用する場合、status_override プロパティが非常に役立ちます。 これにより、アプリケーションで IsEnabledAsyncFeatureGateAttribute のような API を使い続けながら、パーセンタイル割り当てやシードなどのバリアントに付属する新しい機能の恩恵を受けることができます。

{
    "id": "MyVariantFeatureFlag",
    "enabled": true,
    "allocation": {
        "percentile": [
            {
                "variant": "On",
                "from": 10,
                "to": 20
            }
        ],
        "default_when_enabled":  "Off",
        "seed": "Enhanced-Feature-Group"
    },
    "variants": [
        {
            "name": "On"
        },
        {
            "name": "Off",
            "status_override": "Disabled"
        }
    ]
}

上記の例では、機能が常に有効になっています。 現在のユーザーが計算されたパーセンタイルの 10 から 20 の範囲にある場合、On バリアントが返されます。 それ以外の場合は、Off バリアントが返され、status_overrideDisabled と等しいため、その機能は無効とみなされます。

依存関係の挿入のバリアント

バリアント機能フラグは、依存関係の挿入と組み合わせて使用することで、ユーザーごとに異なるサービスの実装を表示できます。 これを行うには、IVariantServiceProvider<TService> インターフェイスを使用します。

IVariantServiceProvider<IAlgorithm> algorithmServiceProvider;
...

IAlgorithm forecastAlgorithm = await algorithmServiceProvider.GetServiceAsync(cancellationToken); 

上記のスニペットでは、IVariantServiceProvider<IAlgorithm> は依存関係の挿入コンテナーから IAlgorithm の実装を取得します。 選択された実装は、以下に依存します。

  • IAlgorithm サービスが登録された機能フラグ。
  • その機能に割り当てられたバリアント。

IVariantServiceProvider<T>IFeatureManagementBuilder.WithVariantService<T>(string featureName) を呼び出すことでアプリケーションに利用できるようになります。 例については、以下を参照してください。

services.AddFeatureManagement() 
        .WithVariantService<IAlgorithm>("ForecastAlgorithm");

上記の呼び出しは IVariantServiceProvider<IAlgorithm> をサービス コレクションで利用できるようにします。 IAlgorithm の実装は、services.AddSingleton<IAlgorithm, SomeImplementation>() のような add メソッドを介して個別に追加する必要があります。 IVariantServiceProvider で使用される IAlgorithm の実装は ForecastAlgorithm のバリアント機能フラグに依存します。 IAlgorithm の実装がサービス コレクションに追加されていない場合、IVariantServiceProvider<IAlgorithm>.GetServiceAsync()null の結果を持つタスクを返します。

{
    // The example variant feature flag
    "id": "ForecastAlgorithm",
    "enabled": true,
    "variants": [
        { 
            "Name": "AlgorithmBeta" 
        },
        ...
    ] 
}

バリアント サービス Alias 属性

[VariantServiceAlias("Beta")]
public class AlgorithmBeta : IAlgorithm
{
    ...
}

バリアント サービス プロバイダーは割り当てられたバリアントに一致する実装の型名を使用します。 バリアント サービスが VariantServiceAliasAttribute で装飾されている場合、この属性で宣言された名前は、このバリアント サービスを参照するために構成で使用する必要があります。

テレメトリ

機能フラグの変更がデプロイされると、多くの場合、アプリケーションへの影響の分析が重要です。 たとえば、可能性のある質問は次のとおりです。

  • 私のフラグは期待どおりに有効または無効になっていますか?
  • 対象ユーザーは、期待どおりに特定の機能にアクセスできていますか?
  • どのバリアントが特定のユーザーに表示されていますか?

この種の質問には、機能フラグ評価イベントの生成と分析を通じて回答できます。 このライブラリでは、System.Diagnostics.Activity API を使用して、機能フラグの評価中にトレース テレメトリを生成します。

テレメトリの有効化

既定では、機能フラグにはテレメトリがありません。 指定された機能フラグに対してテレメトリを発行するには、フラグはテレメトリ生成のために有効であることを宣言する必要があります

appsettings.json で定義された機能フラグの場合は、telemetry プロパティを使用して行われます。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyFeatureFlag",
                "enabled": true,
                "telemetry": {
                    "enabled": true
                }
            }
        ]
    }
}

上記の appsettings スニペットでは、テレメトリを有効にする MyFeatureFlag という名前の機能フラグを定義しています。 これは、enabled を true に設定する telemetry オブジェクトによって示されます。 フラグのテレメトリを発行するには、enabled プロパティの値を true にする必要があります。

機能フラグの telemetry セクションには次のプロパティがあります。

プロパティ 説明
enabled 機能フラグに対してテレメトリを発行するかどうかを指定します。
metadata 機能フラグに関するカスタム メタデータを評価イベントにアタッチするために使用できる、辞書としてモデル化されたキーと値のペアのコレクション。

カスタム テレメトリの発行

機能マネージャーには、"Microsoft.FeatureManagement" という独自の ActivitySource があります。 機能フラグに対して telemetry が有効な場合、機能フラグの評価が開始されるたびに、機能マネージャーは Activity を開始します。 機能フラグの評価が完了すると、機能マネージャーは FeatureFlag という ActivityEvent を現在のアクティビティに追加します。 FeatureFlag イベントは、機能フラグ評価に関する情報を含むタグを持つことになり、これは FeatureEvaluationEvent スキーマ内で定義されているフィールドに従います。

Note

機能フラグの telemetry.metadata で指定されたすべてのキーと値のペアもタグに含まれます。

カスタム テレメトリの発行を有効にするには、ActivityListener を作成し、Microsoft.FeatureManagement アクティビティ ソースをリッスンします。 次の例は、機能管理アクティビティ ソースをリッスンし、機能の評価時にコールバックを追加する方法を示しています。

ActivitySource.AddActivityListener(new ActivityListener()
{
    ShouldListenTo = (activitySource) => activitySource.Name == "Microsoft.FeatureManagement",
    Sample = (ref ActivityCreationOptions<ActivityContext> options) => ActivitySamplingResult.AllData,
    ActivityStopped = (activity) =>
    {
        ActivityEvent? evaluationEvent = activity.Events.FirstOrDefault((activityEvent) => activityEvent.Name == "FeatureFlag");

        if (evaluationEvent.HasValue && evaluationEvent.Value.Tags.Any())
        {
            // Do something.
        }
    }
});

詳細については、「分散トレースを収集する」を参照してください。

Application Insights のテレメトリ パブリッシャー

Microsoft.FeatureManagement.Telemetry.ApplicationInsights パッケージには、Application Insights に機能フラグ評価データを送信する組み込みのテレメトリ パブリッシャーが用意されています。 これを活用するには、以下に示すようにパッケージに参照を追加し、Application Insights テレメトリ パブリッシャーを登録します。

builder.services
    .AddFeatureManagement()
    .AddApplicationInsightsTelemetryPublisher();

Microsoft.FeatureManagement.Telemetry.ApplicationInsights パッケージには、イベントをフラグ評価にリンクできるように、すべてのイベントに自動的に TargetingId のタグを付けるテレメトリ初期化子が用意されています。 テレメトリ初期化子 TargetingTelemetryInitializer を使用するには、それをアプリケーションのサービス コレクションに追加します。

builder.Services.AddSingleton<ITelemetryInitializer, TargetingTelemetryInitializer>();

Note

TargetingTelemetryInitializer が期待どおりに機能するようにするには、以下で説明する TargetingHttpContextMiddleware を使用する必要があります。

現在のアクティビティでターゲット設定コンテキストの永続化を有効にするには、TargetingHttpContextMiddleware を使用できます。

app.UseMiddleware<TargetingHttpContextMiddleware>();

この使用方法の例は、VariantAndTelemetryDemo の例にあります。

前提条件

このテレメトリ パブリッシャーは、Application Insights が既に設定され、アプリケーション サービスとして登録されていることに依存します。 たとえば、これはアプリケーションの例のこちらで行われています。

このテレメトリ パブリッシャーは、Application Insights が既に設定され、アプリケーション サービスとして登録されていることに依存します。

キャッシュ

機能の状態は IConfiguration システムによって提供されます。 キャッシュや動的な更新は、構成プロバイダーによって処理されることが期待されています。 機能マネージャーは、機能が有効であると確認されるたびに、IConfiguration に機能の状態の最新の値を要求します。

スナップショット

要求の有効期間中、機能の状態が一貫性を維持することが必要なシナリオがあります。 標準の IFeatureManager から返される値は、要求中に IConfiguration ソースが更新された場合に変更される可能性があります。 これは、IFeatureManagerSnapshot を使用することで防ぐことができます。 IFeatureManagerSnapshot は、IFeatureManager と同じ方法で取得できます。 IFeatureManagerSnapshotIFeatureManager のインターフェイスを実装していますが、要求中に機能の最初に評価された状態をキャッシュし、有効期間中に機能の同じ状態を返します。

カスタム機能プロバイダー

カスタム機能プロバイダーを実装すると、開発者はデータベースや機能管理サービスなどのソースから機能フラグをプルできます。 既定で使用される機能プロバイダーは、.NET Core の構成システムから機能フラグをプルします。 これにより、appsettings.json ファイルまたは Azure App Configuration のような構成プロバイダーで機能を定義できます。 この動作に置き換えることで、機能の定義の読み込み元を完全に制御できます。

機能の定義の読み込みをカスタマイズするには、IFeatureDefinitionProvider インターフェイスを実装する必要があります。

public interface IFeatureDefinitionProvider
{
    Task<FeatureDefinition> GetFeatureDefinitionAsync(string featureName);

    IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync();
}

IFeatureDefinitionProvider の実装を使用するには、機能管理を追加する前にサービス コレクションに追加する必要があります。 次の例では、InMemoryFeatureDefinitionProvider という名前の IFeatureDefinitionProvider の実装を追加しています。

services.AddSingleton<IFeatureDefinitionProvider, InMemoryFeatureDefinitionProvider>()
        .AddFeatureManagement()

次のステップ

アプリケーションで機能フラグを使用する方法については、次のクイックスタートに進んでください。

機能フィルターの使用方法について学ぶには、次のチュートリアルに進んでください。

バリアント機能フラグを使用して実験を実行する方法については、次のチュートリアルに進んでください。