.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 延伸模組

    • 路由
    • 篩選
    • 動作屬性

    .NET 功能管理程式庫是開放原始碼。 如需詳細資訊,請造訪 GitHub 存放庫

功能旗標

功能旗標是由兩個部分所組成,一個名稱和一份用來開啟功能的功能篩選清單。

功能篩選

功能篩選會定義何時應啟用功能的案例。 評估功能是否開啟或關閉時,會周遊其功能篩選清單,直到其中一個篩選條件決定應啟用功能為止。 此時,功能會被視為已啟用且周遊功能篩選會停止。 如果沒有功能篩選指出應該啟用功能,則會將其視為已停用。

例如,可以設計 Microsoft Edge 瀏覽器功能篩選。 只要 HTTP 要求來自 Microsoft Edge,此功能篩選就會啟用其所附加的任何功能。

功能旗標組態

.NET Core 組態系統可用來判斷功能旗標的狀態。 這個系統的基礎是 IConfigurationIConfiguration 的任何提供者都可以作為功能旗標程式庫的功能狀態提供者。 此系統可啟用從 appsettings.json 到 Azure 應用程式組態等各種案例。

功能旗標宣告

功能管理程式庫支援 appsettings.json 作為功能旗標來源,因為它是 .NET Core IConfiguration 系統的提供者。 以下是用來在 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 區段會由慣例用來載入功能旗標設定。 在上一節中,我們看到三個不同的功能。 功能會使用 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 屬性可用來判斷篩選條件在評估功能的狀態時,是否應該使用 AnyAll 邏輯。 如果未指定 RequirementType,則預設值為 Any

  • Any 表示只有一個篩選條件需要評估為 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"
            }
        }
    ]
}

在上述範例中,FeatureW 指定了 AllRequirementType,這表示其所有篩選條件都必須評估為 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"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

注意

如果在組態中找到 feature_management 區段,則會忽略 FeatureManagement 區段。

功能管理程式庫支援 appsettings.json 作為功能旗標來源,因為它是 .NET Core IConfiguration 系統的提供者。 功能旗標會使用 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 陣列中。 在上一節中,我們看到我們提供了三個不同的功能。 功能旗標具有 idenabled 屬性。 id 是用來識別和參考功能旗標的名稱。 enabled 屬性會指定功能旗標的啟用狀態。 如果 enabled為 false,則功能為 [開啟]。 如果 enabled 為 true,則功能的狀態取決於 conditions。 如果沒有 conditions,則功能為 [開啟]。 如果有 conditions 且符合,則此功能為 [開啟]。 如果有 conditions 且不符合,則此功能為 [關閉]conditions 屬性會宣告用來動態啟用功能的條件。 功能會在 client_filters 陣列中定義其功能篩選。 FeatureV 指定名為 Microsoft.TimeWindow 的功能篩選。 這是可設定功能篩選的範例。 我們可以在範例中看到篩選條件具有 Parameters 屬性。 這是用來設定篩選條件。 在此情況下,會設定要成為作用中功能的開始和結束時間。

進階:功能旗標名稱中禁止使用冒號 ':'。

RequirementType

conditionsrequirement_type 屬性可用來判斷篩選條件在評估功能的狀態時,是否應該使用 AnyAll 邏輯。 如果未指定 requirement_type,則預設值為 Any

  • Any 表示只有一個篩選條件需要評估為 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"
                }
            }
        ]
    }
}

在上述範例中,FeatureW 指定了 Allrequirement_type,這表示其所有篩選條件都必須評估為 true,才能啟用此功能。 在此情況下,此功能將會在指定的時間範圍內針對 50% 的使用者啟用。

.NET 功能管理結構描述

在舊版中,功能管理程式庫的主要結構描述是 .NET feature management schema。 從 v4.0.0 開始,.NET 功能管理結構描述不支援包含變體和遙測的新功能。

注意

如果可以在 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] 區段不存在,則設定會視為空白。

注意

您也可以將區段傳遞至 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>

注意

如果指定了 variant,則應該只指定「一個」功能。

根據預設,所有列出的功能都必須啟用,才能轉譯功能標籤。 您可以藉由新增 requirement 屬性來覆寫此行為,如下列範例所示。

注意

如果 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 動作篩選條件。

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

上述程式碼會新增名為 SomeMvcFilter 的 MVC 篩選條件。 只有在「FeatureX」已啟用時,才會在 MVC 管線內觸發此篩選條件。

Razor Pages

MVC Razor 頁面可能需要啟用指定的功能或其中一個功能清單才能執行。 這可以使用可在 Microsoft.FeatureManagement.Mvc 命名空間中找到的 FeatureGateAttribute 來完成。

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

上述程式碼會設定 Razor 頁面,以要求啟用「FeatureX」。 如果未啟用此功能,頁面會產生 HTTP 404 (NotFound) 結果。

在 Razor 頁面上使用時,FeatureGateAttribute 必須放在頁面處理常式類型上。 它不能放在個別的處理常式方法上。

應用程式建置

功能管理程式庫可用來新增應用程式分支和中介軟體,這些分支和中介軟體會根據功能狀態有條件地執行。

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

透過上述呼叫,應用程式會新增中介軟體元件,只有在啟用功能「FeatureX」時才會出現在要求管線中。 如果在執行階段期間啟用/停用此功能,則可以動態地變更中介軟體管線。

這會建置更泛型的功能以根據功能來為整個應用程式建立分支。

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

實作功能篩選

建立功能篩選可讓您根據您定義的準則來啟用功能。 若要實作功能篩選,必須實作 IFeatureFilter 介面。 IFeatureFilter 具有名為 EvaluateAsync 的單一方法。 當功能指定其可以針對功能篩選啟用時,就會呼叫 EvaluateAsync 方法。 如果 EvaluateAsync 傳回 true,表示應該啟用功能。

下列程式碼片段示範如何新增自訂功能篩選 MyCriteriaFilter

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

功能篩選是藉由 AddFeatureManagement 傳回 IFeatureManagementBuilder 時呼叫 AddFeatureFilter<T> 來註冊。 這些功能篩選可以存取服務集合內存在的服務,而這些服務可用來新增功能旗標。 相依性插入可用來擷取這些服務。

注意

在功能旗標設定中參考篩選時 (例如 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
    }
}

篩選別名屬性

為功能旗標註冊功能篩選時,組態中使用的別名會是具有 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

注意

單一功能篩選介面只能由單一類型實作。 嘗試新增實作多個功能篩選介面的功能篩選會導致 ArgumentException

使用相同的別名使用內容相關和非內容相關的篩選

IFeatureFilterIContextualFeatureFilter 的篩選可以共用相同的別名。 具體而言,您可以有一個篩選別名,由 0 或 1 IFeatureFilter 和 0 或 N IContextualFeatureFilter<ContextType> 共用,只要最多有一個適用於 ContextType 的篩選即可。

下一段說明在應用程式中註冊相同名稱的內容相關和非內容相關的篩選時,選取篩選的程序。

假設您有一個稱為 FilterA 的非內容相關的篩選,以及兩個內容相關的篩選 FilterB 和 FilterC,分別接受 TypeBTypeC 內容。 這三個篩選都會共用相同的別名 SharedFilterName

您也有功能旗標 MyFeature,其組態中使用功能篩選 SharedFilterName

如果所有三個篩選都已註冊:

  • 當您呼叫 IsEnabledAsync("MyFeature"),FilterA 會用來評估功能旗標。
  • 當您呼叫 IsEnabledAsync("MyFeature", context),如果內容的類型為 TypeB,則會使用 FilterB。 如果內容的類型為 TypeC,則會使用 FilterC
  • 當您呼叫 IsEnabledAsync("MyFeature", context),如果內容的類型為 TypeF,則會使用 FilterA

.NET 內建功能篩選

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 參數中指定週期性規則。

注意

StartEnd 必須同時指定,才能啟用 Recurrence

"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 (定期模式重複的時間長度)。

週期模式

有兩種可能的定期模式類型:DailyWeekly。 例如,時間範圍可以重複「每天」、「每三天」、「每星期一」或「每隔週星期五」。

視類型而定,Pattern 的特定欄位為必要、選擇性或忽略。

  • Daily

    每天定期模式會導致時間範圍根據每次發生之間的天數重複。

    屬性 相關性 描述
    類型 必要 必須設定為 Daily
    間隔 選擇性 指定每次發生之間的天數。 預設值為 1。
  • Weekly

    每週定期模式會導致根據每組發生次數之間的週數,在一週的相同一天或幾天重複時間範圍。

    屬性 相關性 描述
    類型 必要 必須設定為 Weekly
    DaysOfWeek 必要 指定事件發生在星期幾。
    間隔 選擇性 指定每組發生次數之間的週數。 預設值為 1。
    FirstDayOfWeek 選擇性 指定哪一天會被視為一週的第一天。 預設值為 Sunday

    下列範例會每隔週星期一和星期二重複時間範圍

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

注意

Start 必須是符合定期模式的有效第一次發生。 此外,時間範圍持續時間不能超過其發生頻率。 例如,每天重複 25 小時的時間範圍是無效的。

週期範圍

有三種可能的週期範圍類型:NoEndEndDateNumbered

  • NoEnd

    NoEnd 範圍會導致週期無限期發生。

    屬性 相關性 描述
    類型 必要 必須設定為 NoEnd
  • EndDate

    EndDate 範圍會使時間範圍發生在符合適用模式的所有天數,直到結束日期為止。

    屬性 相關性 描述
    類型 必要 必須設定為 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 範圍會導致時間範圍發生固定次數 (根據模式)。

    屬性 相關性 描述
    類型 必要 必須設定為 Numbered
    NumberOfOccurrences 必要 指定發生次數。

    下列範例會在星期一和星期二重複時間範圍,直到於 4 月 1 日 (星期一)、4 月 2 日 (星期二) 和 4 月 8 日 (星期一) 分別發生三次。

    "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"
                        ]
                    }
                }
            }
        }
    ]
}

功能篩選別名命名空間

所有內建功能篩選別名都在 Microsoft 功能篩選命名空間中。 這是為了避免與其他可能共用相同別名的功能篩選發生衝突。 功能篩選命名空間的區段會依 '.' 字元分割。 功能篩選可以透過其完整別名來參考,例如 Microsoft.Percentage,或最後一個區段,在此情況下 Microsoft.PercentagePercentage

目標設定

目標是功能管理策略,可讓開發人員逐漸向使用者群推出新功能。 此策略是建立在以一組稱為目標「對象」的使用者為目標的概念之上。 對象由特定使用者、群組、排除的使用者/群組和整個使用者群的指定百分比所組成。 對象中包含的群組可以進一步細分為其成員總數的百分比。

下列步驟示範新 'Beta' 功能的漸進式推出範例:

  1. 個人使用者 Jeff 和 Alicia 被授與 Beta 的存取權
  2. 另一位使用者 Mark 要求加入並包含在內。
  3. Beta 中包含 20% 稱為「Ring1」使用者的群組。
  4. Beta 中包含的「Ring1」使用者數目高達 100%。
  5. Beta 中包含 5% 的使用者群。
  6. 發行百分比高達 100%,且功能已完全推出。

此推出功能的策略會內建至程式庫,透過內含的 Microsoft.Targeting 功能篩選。

Web 應用程式中的目標

FeatureFlagDemo 範例專案中提供使用目標功能篩選的 範例 Web 應用程式。

若要開始在應用程式中使用 TargetingFilter,它必須新增至應用程式的服務集合,如同任何其他功能篩選。 與其他內建篩選不同,TargetingFilter 依賴於另一個服務新增至應用程式的服務集合。 該服務為 ITargetingContextAccessor

Microsoft.FeatureManagement.AspNetCore 提供 ITargetingContextAccessor預設實作,以從要求的 HttpContext 擷取目標資訊。 您可以在使用 IFeatureManagementBuilder 上的非泛型 WithTargeting 多載設定目標時,使用預設目標內容存取子。

預設目標內容存取子,而 TargetingFilter 會在 IFeatureManagementBuilder 上藉由呼叫 WithTargeting 來註冊。

services.AddFeatureManagement()
        .WithTargeting();

您也可藉由呼叫 WithTargeting<T> 來註冊 ITargetingContextAccessorTargetingFilter 的自訂實作。 以下是在 Web 應用程式中設定功能管理的範例,以搭配稱為 ExampleTargetingContextAccessorITargetingContextAccessor 實作使用 TargetingFilter

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

ITargetingContextAccessor

若要在 Web 應用程式中使用 TargetingFilter,則需要 ITargetingContextAccessor 的實作。 這是因為執行目標評估時,需要例如目前正在評估的使用者等內容相關資訊。 這項資訊稱為 TargetingContext。 不同的應用程式可能會從不同位置擷取此資訊。 應用程式可能會提取目標內容的一些常見範例是要求的 HTTP 內容或資料庫。

Microsoft.FeatureManagement.AspNetCore 套件所提供的 DefaultHttpTargetingContextAccessor 是從應用程式的 HTTP 內容擷取目標內容資訊的範例。 它會從 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,因此此篩選的組態與該區段中所述的設定一致。

TargetingConsoleApp 範例專案中有一個在主控台應用程式中使用 ContextualTargetingFilter 的範例。

目標評估選項

選項可用來自訂在所有功能之間執行目標評估的方式。 設定功能管理時可以設定這些選項。

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。 另一個選項是使用 NET 的組態繫結模式將組態繫結至物件。

IConfigurationSection variantConfiguration = variant.Configuration;

MyFeatureSettings settings = new MyFeatureSettings();

variantConfiguration.Bind(settings);

傳回的變體取決於目前正在評估的使用者,而該資訊會從 TargetingContext 的執行個體中取得。 呼叫 GetVariantAsync 時可以傳入此內容,或者如果已註冊,則可以從 ITargetingContextAccessor 的實作中自動擷取。

變體功能旗標宣告

相較於一般功能旗標,變體功能旗標有兩個額外的屬性:variantsallocationvariants 屬性是一個數字,其中包含為這項功能定義的變體。 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"
                    } 
                ]
            }
        ]
    }
}

定義變體

每個變體都有兩個屬性:名稱和組態。 此名稱是用來參考特定變體,而組態是該變體的值。 您可以使用 configuration_value 屬性來設定組態。 configuration_value 是可以是字串、數位、布林值或組態物件的內嵌組態。 如果未指定 configuration_value,傳回的 variant 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 指定變體和群組清單。 如果使用者至少在其中一個群組中,則會指派變體。
percentile 指定變體和使用者計算百分比必須符合才能指派該變體的百分比範圍。
seed 計算 percentile 百分比依據的值。 如果使用相同的 seed 值,特定使用者的百分比計算在所有功能上都會相同。 如果未指定 seed,則會根據功能名稱建立預設種子。

在上述範例中,如果未啟用此功能,功能管理員會將標示為 default_when_disabled 的變體指派給目前使用者,在此案例中為 Small

如果啟用此功能,功能管理員將會依該順序檢查 usergrouppercentile 配置,以指派變體。 在此特定範例中,如果評估的使用者名為 Marsha,則在名為 Ring1 的群組中,或使用者碰巧落在第 0 到 10 個百分位數之間,則會將指定的變異指派給使用者。 在此情況下,所有這些情況都會傳回 Big 變體。 如果這些配置都不相符,則會為使用者指派 default_when_enabled 變體,也就是 Small

配置邏輯與 Microsoft.Targeting 功能篩選類似,但目標中有一些參數不在配置中,反之亦然。 目標的結果與配置無關。

注意

若要允許配置功能變體,您必須註冊 ITargetingContextAccessor。 這可以透過呼叫 WithTargeting<T> 方法來完成。

使用變體覆寫已啟用狀態

您可以使用變體來覆寫功能旗標的已啟用狀態。 這可讓變體有機會延伸功能旗標的評估。 在具有變體的旗標上呼叫 IsEnabled 時,功能管理員會檢查指派至目前使用者的變體是否已設定為覆寫結果。 這是使用選用的變體屬性 status_override 來完成。 根據預設,這個屬性會設定為 None,這表示變數不會影響旗標是否被視為已啟用或停用。 將 status_override 設定為 Enabled 可讓變數在選擇時覆寫要啟用的旗標。 將 status_override 設定為 Disabled 可提供相反的功能,因此會在選擇變體時停用旗標。 無法覆寫具有 falseenabled 狀態的功能。

如果您使用具有二進位變體的功能旗標,則 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_override 等於 Disabled,而功能現在會被視為已停用。

相依性插入中的變體

變體功能旗標可以與相依性插入搭配使用,以呈現不同使用者服務的不同實作。 此作業可使用 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>()IVariantServiceProvider 所使用的 IAlgorithm 實作取決於 ForecastAlgorithm 變體功能旗標。 如果未將 IAlgorithm 的實作加入至服務集合,則 IVariantServiceProvider<IAlgorithm>.GetServiceAsync() 會傳回具有 null 結果的工作。

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

變體服務別名屬性

[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 模型化為字典的索引鍵/值組集合,可用來將功能旗標的相關自訂中繼資料附加至評估事件。

自訂遙測發佈

功能管理員有自己的 ActivitySource,名為 "Microsoft.FeatureManagement"。 如果 telemetry 已啟用功能旗標,每當功能旗標評估開始時,功能管理員就會啟動 Activity。 功能旗標評估完成時,功能管理員會將名為 FeatureFlagActivityEvent 新增至目前活動。 FeatureFlag 事件會有標籤,其中包含功能旗標評估的相關資訊,並遵循 FeatureEvaluationEvent 結構描述中定義的欄位。

注意

功能旗標的 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>();

注意

為了確保 TargetingTelemetryInitializer 如預期般運作,應使用下面說明的 TargetingHttpContextMiddleware

若要在目前活動中啟用目標內容的保存,您可以使用 TargetingHttpContextMiddleware

app.UseMiddleware<TargetingHttpContextMiddleware>();

您可以在 EvaluationDataToApplicationInsights 範例中找到其使用方式的範例。

必要條件

此遙測發行者取決於已設定且註冊為應用程式服務的 Application Insights。 例如,這是在範例應用程式中的這裡完成的。

快取功能

功能狀態是由 IConfiguration 系統提供。 任何快取和動態更新都會預期由組態提供者處理。 每當檢查要啟用的功能時,功能管理員會針對功能狀態的最新值要求 IConfiguration

快照式

在某些情況下,要求功能的狀態在要求的存留期內保持一致。 如果 IConfiguration 的提取來源在要求期間更新,則從標準 IFeatureManager 傳回的值可能會變更。 您可以使用 IFeatureManagerSnapshot 來防止這種情況。 IFeatureManagerSnapshot 可以用與 IFeatureManager 相同的方式來擷取。 IFeatureManagerSnapshot 會實作 IFeatureManager 的介面,但其會在要求期間快取功能的第一個評估狀態,並在其存留期間傳回功能的相同狀態。

自訂功能提供者

實作自訂功能提供者可讓開發人員從資料庫或功能管理服務等來源提取功能旗標。 預設使用的內含功能提供者會從 .NET Core 的組態系統提取功能旗標。 這可讓功能定義在 appsettings.json 檔案或組態提供者中,例如 Azure 應用程式組態。 您可以替代此行為,以完整控制從中讀取功能定義的位置。

若要自訂功能定義的載入,則必須實作 IFeatureDefinitionProvider 介面。

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

    IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync();
}

若要使用 IFeatureDefinitionProvider 的實作,必須先將其新增至服務集合,然後才能新增功能管理。 下列範例會新增名為 InMemoryFeatureDefinitionProviderIFeatureDefinitionProvider 實作。

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

下一步

若要了解如何在應用程式中使用功能旗標,請繼續進行下列快速入門。

若要了解如何使用功能篩選,請繼續進行下列教學課程。

若要了解如何使用變體功能旗標執行實驗,請繼續進行下列教學課程。