.NET 功能管理

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 功能管理库是开源的。 有关详细信息,请参阅 FeatureManagement-Dotnet GitHub 存储库。

功能标志

可以启用或禁用功能标志。 可以使用功能筛选器来有条件地设置标志的状态。

功能筛选器

功能筛选器定义应启用功能的场景。 若要评估某个功能的状态,将遍历其功能筛选器列表,直到其中一个筛选器确定启用该功能。 此时,特征筛选器的遍历停止。 如果没有功能筛选器指示应启用该功能,则它被视为已禁用。

例如,假设你设计了Microsoft Edge 浏览器功能筛选器。 如果 HTTP 请求来自 Microsoft Edge,则功能筛选器将激活它附加到的任何功能。

功能标志配置

.NET Core 配置系统用于确定功能标志的状态。 此系统的基础是 IConfiguration 接口。 IConfiguration 的任何提供程序都可以用作功能标志库的功能状态提供程序。 此系统支持从 appsettings.json 配置文件到 Azure 应用配置等各种方案。

功能标志声明

功能管理库支持将 appsettings.json 配置文件作为特性标志源,因为它是 .NET Core IConfiguration 系统的提供程序。 使用 Microsoft Feature Management schema 声明特性标志。 此架构与源语言无关,在所有 Azure 功能管理库中都受支持。

以下示例中的代码在 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": "Sun, 01 Jun 2025 13:59:59 GMT",
                                "End": "Fri, 01 Aug 2025 00:00:00 GMT"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

feature_management JSON 文档的部分按照惯例用于加载功能标志设置。 必须在此部分中列出 feature_flags 数组中的功能标志对象。 此代码列出了三个功能标志。 每个功能标志对象都有一个id属性和一个enabled属性。

  • id值是用于标识和引用特性标志的名称。
  • enabled 属性指定功能标志的已启用状态。

如果 enabledfalse,则此功能处于关闭状态。 enabled如果是true,则功能的状态取决于属性conditions。 该 conditions 属性声明用于动态启用该功能的条件。

  • 如果功能标志没有 conditions 属性,则该功能处于打开中。
  • 如果特征标志具有 conditions 属性及其条件,则该功能处于打开状态。
  • 如果功能标志具有属性 conditions 且其条件未满足,则该功能处于关闭状态。

特征筛选器在 client_filters 数组中定义。 在前面的代码中, FeatureV 功能标志具有一个名为 Microsoft.TimeWindow的功能筛选器。 此筛选器是可配置的功能筛选器的示例。 在此代码中,此筛选器具有属性 parameters 。 此属性用于配置筛选器。 在本例中,将配置功能处于活动状态的开始和结束时间。

高级: 特征标志名称中禁止冒号字符 (:)。

要求类型

conditions 属性中,该 requirement_type 属性用于确定筛选器在评估功能状态时应使用 Any 还是 All 逻辑。 如果未指定 requirement_type,则默认值为 Any。 这些 requirement_type 值会导致以下行为:

  • Any:只需一个筛选器评估为true即可启用功能。
  • All:每个筛选器评估结果为 true,才能启用该功能。

一次requirement_typeAll的更改改变了筛选器的遍历方式:

  • 如果未列出筛选器,则禁用该功能。
  • 如果列出了筛选器,则会遍历筛选器,直到一个筛选器的条件指定应禁用该功能。 如果没有筛选器指示应禁用该功能,则它被视为已启用。
{
    "id": "FeatureW",
    "enabled": true,
    "conditions": {
        "requirement_type": "All",
        "client_filters": [
            {
                "name": "Microsoft.TimeWindow",
                "parameters": {
                    "Start": "Sun, 01 Jun 2025 13:59:59 GMT",
                    "End": "Fri, 01 Aug 00:00:00 GMT"
                }
            },
            {
                "name": "Microsoft.Percentage",
                "parameters": {
                    "Value": "50"
                }
            }
        ]
    }
}

在此示例中, FeatureW 功能标志的 requirement_type 值为 All. 因此,所有筛选器都必须评估为 true ,才能启用该功能。 在这种情况下,该功能在指定时间范围内为 50% 的用户启用。

处理多个配置源

从 v4.3.0 开始,您可以选择对 Azure 模式功能标志(feature_management 部分)进行自定义合并。 当多个配置源中出现相同的功能标志 ID 时,内置 ConfigurationFeatureDefinitionProvider 类的实例会根据配置提供程序注册顺序合并这些定义。 如果存在冲突,则使用最后一个功能标志定义。 此行为不同于 .NET 中默认的基于数组索引的合并方式。

以下代码通过依赖项注入启用自定义功能标志配置合并:

IConfiguration configuration = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .AddJsonFile("appsettings.prod.json")
    .Build();

services.AddSingleton(configuration);
services.AddFeatureManagement();
services.Configure<ConfigurationFeatureDefinitionProviderOptions>(o =>
{
        o.CustomConfigurationMergingEnabled = true;
});

你还可以在构造ConfigurationFeatureDefinitionProvider的实例时启用自定义合并。

var featureManager = new FeatureManager(
    new ConfigurationFeatureDefinitionProvider(
            configuration,
            new ConfigurationFeatureDefinitionProviderOptions
            {
                    CustomConfigurationMergingEnabled = true
            }));

示例行为:

// appsettings.json
{
    "feature_management": {
        "feature_flags": [
            { "id": "FeatureA", "enabled": true },
            { "id": "FeatureB", "enabled": false }
        ]
    }
}

// appsettings.prod.json (added later in ConfigurationBuilder)
{
    "feature_management": {
        "feature_flags": [
            { "id": "FeatureB", "enabled": true }
        ]
    }
}

启用自定义合并时,FeatureA 将保持启用状态,FeatureB 被设定为启用,因为使用了最后一个声明。 使用默认的 .NET 合并(禁用自定义合并)时,数组按索引合并。 如果源不按位置对齐,此方法可能会产生意外的结果。

.NET 功能管理架构

在以前版本的功能管理库中,主架构是 .NET 功能管理架构

从库版本 4.0.0 开始,.NET 功能管理架构不支持新功能(包括变体和遥测)。

注意

如果功能标志配置包含同时在feature_management节和FeatureManagement节中列出的声明,则采用feature_management节中的声明。

消耗

在基本实现中,功能管理会检查是否启用了功能标志。 然后,它会根据结果执行操作。 此检查是通过IsEnabledAsync方法来完成IVariantFeatureManager

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

服务注册

功能管理依赖于 .NET Core 依赖项注入。 如以下代码所示,可以使用标准约定来注册功能管理服务:

using Microsoft.FeatureManagement;

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

默认情况下,功能管理器从 feature_management .NET Core 配置数据或 FeatureManagement 部分检索功能标志配置。 如果两个部分都不存在,则配置被视为空。

注意

您还可以通过将分区传递给 AddFeatureManagement 来指定应从其他配置部分检索功能标志配置。 以下示例指定功能管理器应改为从名为MyFeatureFlags的节中读取:

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

依赖项注入

将功能管理库与 MVC 配合使用时,可以使用依赖项注入获取实现 IVariantFeatureManager 的对象。

public class HomeController : Controller
{
    private readonly IVariantFeatureManager _featureManager;

    public HomeController(IVariantFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }
}

范围限定的功能管理服务

该方法在 AddFeatureManagement 应用程序中将功能管理服务添加为单一实例。 某些方案要求将功能管理服务添加为作用域服务。 例如,你可能想要使用使用范围服务的功能筛选器来获取上下文信息。 在这种情况下,应使用 AddScopedFeatureManagement 该方法。 此方法可确保将功能管理服务(包括功能筛选器)添加为有范围的服务。

services.AddScopedFeatureManagement();

ASP.NET Core 集成

功能管理库在 ASP.NET Core 和 MVC 中提供功能,可在 Web 应用程序中启用常见功能标志方案。 可以通过引用 Microsoft.FeatureManagement.AspNetCore NuGet 包来提供这些功能。

控制器和操作

MVC 控制器和作可能需要启用给定功能或任何功能列表之一才能运行。 可以使用对象来满足此要求 FeatureGateAttributeFeatureGateAttribute 类定义在 Microsoft.FeatureManagement.Mvc 命名空间中。

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

在前面的示例中,类 HomeController 受到 FeatureX 的控制。 HomeController 只能在FeatureX 功能启用时运行。

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

在前面的示例中,Index MVC操作只能在FeatureX启用该功能时运行。

禁用的操作处理

当 MVC 控制器或动作因其指定的功能未启用而被阻止时,将调用已注册的 IDisabledFeaturesHandler 实现。 默认情况下,会注册一个极简处理程序,该程序会返回 HTTP 404 错误。 可以在注册功能标志时使用 IFeatureManagementBuilder 替代此处理程序。

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

视图

在 MVC 视图中,可以使用 <feature> 标记来有条件地呈现内容。 可以根据是否启用某个功能或是否分配了某个功能的特定变体来基于呈现条件。 有关详细信息,请参阅本文后面的 Variants

<feature name="FeatureX">
  <p>This content appears only when 'FeatureX' is enabled.</p>
</feature>
<feature name="FeatureX" variant="Alpha">
  <p>This content appears only when variant 'Alpha' of 'FeatureX' is assigned.</p>
</feature>

如果想要在禁用功能或功能集时显示内容,还可以否定标记帮助程序评估。 如果指定 negate="true",如以下示例所示,则内容仅在 FeatureX 被禁用时呈现。

<feature negate="true" name="FeatureX">
  <p>This content appears only when 'FeatureX' is disabled.</p>
</feature>
<feature negate="true" name="FeatureX" variant="Alpha">
  <p>This content appears only when variant 'Alpha' of 'FeatureX' isn't assigned.</p>
</feature>

可以使用 <feature> 标记来引用多个功能。 为此,请在属性中 name 指定以逗号分隔的功能列表。

<feature name="FeatureX,FeatureY">
  <p>This content appears only when 'FeatureX' and 'FeatureY' are enabled.</p>
</feature>

默认情况下,必须为要呈现的功能标记启用所有列出的功能。 可以通过添加 requirement 属性来替代此行为,如以下示例所示。

<feature name="FeatureX,FeatureY" requirement="Any">
  <p>This content appears only when 'FeatureX,' 'FeatureY,' or both are enabled.</p>
</feature>

也可以使用 <feature> 标记来引用多个变体。 为此,请使用 requirementAny 并在属性中 variant 指定以逗号分隔的变体列表。

<feature name="FeatureX" variant="Alpha,Beta" requirement="Any">
  <p>This content appears only when variant 'Alpha' or 'Beta' of 'FeatureX' is assigned.</p>
</feature>

注意

  • 如果指定变体,应仅指定 一项 功能。
  • 如果指定多个变体并使用 requirementAnd,则会引发错误。 无法分配多个变体。

<feature> 标记需要标记帮助程序才能工作。 若要使用该标记,请将功能管理标记帮助程序添加到 _ViewImports.cshtml 文件。

@addTagHelper *, Microsoft.FeatureManagement.AspNetCore

MVC 筛选器

可以根据功能状态,有条件地设置和应用MVC动作过滤器。 若要设置这些筛选器,请以功能感知的方式注册它们。 功能管理流水线支持实现 IAsyncActionFilter 接口的异步 MVC 动作过滤器。

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

前面的代码注册名为 的 SomeMvcFilterMVC 筛选器。 仅当启用了 MVC 管道 FeatureX 时,才会触发此筛选器。

Razor 页面

MVC Razor 页面可能需要启用给定功能或任何功能列表之一才能运行。 可以使用对象添加此要求 FeatureGateAttribute 。 类 FeatureGateAttribute 定义在命名空间 Microsoft.FeatureManagement.Mvc 中。

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

以上代码设置了一个 Razor 页面,并要求启用 FeatureX。 如果未启用该功能,页面将生成 HTTP 404 (NotFound) 结果。

在 Razor 页面上使用 FeatureGateAttribute 对象时,必须在页面处理程序类型上添加 FeatureGateAttribute。 不能将其放在单个处理程序方法上。

应用程序生成

可以使用功能管理库添加基于功能状态有条件运行的应用程序分支和中间件。

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

在前面的代码中,如果启用了FeatureX功能,应用程序会在请求管道中添加一个中间件组件。 如果在运行时启用或禁用该功能,则可以动态更改中间件管道。

如以下代码所示,此功能利用更为通用的功能,基于特性对整个应用程序进行分支。

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

实现功能筛选器

创建功能筛选器提供了一种基于所定义条件启用功能的方法。 若要实现功能筛选器,必须实现 IFeatureFilter 接口。 IFeatureFilter 有一个名为 EvaluateAsync 的方法。 当功能指定可为功能筛选器启用它时,将调用 EvaluateAsync 方法。 如果 EvaluateAsync 返回 true,则应启用该功能。

以下代码演示如何添加一个名为MyCriteriaFilter的自定义功能筛选器。

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

可以通过调用AddFeatureFilter<T>,在AddFeatureManagement返回的IFeatureManagementBuilder实现上注册功能筛选器。 功能筛选器有权访问用于添加功能标志的服务集合中的服务。 可以使用依赖项注入来检索这些服务。

注意

在功能标志设置(例如 ,appsettings.json) 中引用筛选器时,应省略 Filter 类型名称的一部分。 有关详细信息,请参阅本文后面的 筛选器别名属性

参数化功能筛选器

某些功能筛选器需要参数来评估是否应启用某个功能。 例如,浏览器功能筛选器可能会为一组特定浏览器打开一项功能。 你可能想要在 Microsoft 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();

        //
        // Use the settings to check whether the request is from a browser in BrowserFilterSettings.AllowedBrowsers.
    }
}

筛选器别名属性

为功能标志注册功能筛选器时,在配置中使用的别名是功能筛选器类型的名称,去掉后缀 Filter(如果有)。 例如,在配置中应将MyCriteriaFilter替换为MyCriteria

{
    "id": "MyFeature",
    "enabled": true,
    "conditions": {
        "client_filters": [
            {
                "name": "MyCriteria"
            }
        ]
    }
}

可以使用类替代此名称 FilterAliasAttribute 。 若要声明在配置中使用的名称以引用功能标志中的功能筛选器,可以使用此属性修饰功能筛选器。

缺少功能筛选器

假设你配置了一个功能以针对特定功能筛选器启用。 如果未注册该功能筛选器,则会在评估该功能时引发异常。 如以下代码所示,可以使用功能管理选项禁用异常。

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

使用 HttpContext

功能筛选器可以根据 HTTP 请求的属性评估是否应启用某个功能。 此检查是通过检查 HTTP 上下文执行的。 如下代码所示,功能筛选器可以通过依赖注入获取到 HTTP 上下文的引用,以便获取IHttpContextAccessor的实现。

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.AddHttpContextAccessor();
    …
}

高级:IHttpContextAccessorHttpContext不应在服务器端 Blazor 应用的 Razor 组件中使用。 建议在 Blazor 应用中传递 HTTP 上下文的方法是将数据复制到一个范围服务中。 对于 Blazor 应用,你应该使用 AddScopedFeatureManagement 来注册功能管理服务。 有关详细信息,请参阅本文前面的 作用域功能管理服务

提供功能评估的上下文

控制台应用程序中没有诸如 HttpContext 之类的环境上下文,这使得特性筛选器无法用来检查特性是否应启用。 在这种情况下,应用程序需要提供一个对象,该对象表示功能管理系统的上下文供功能筛选器使用。 您可以使用 IVariantFeatureManager.IsEnabledAsync<TContext>(string featureName, TContext appContext) 提供此上下文。 若要评估功能的状态,功能筛选器可以使用 appContext 提供给功能管理器的对象。

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

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

上下文特征筛选器

上下文功能筛选器可实现 IContextualFeatureFilter<TContext> 接口。 这些特性筛选器可以利用在调用 IVariantFeatureManager.IsEnabledAsync<TContext> 时传入的上下文信息。 中的TContextIContextualFeatureFilter<TContext>类型参数描述筛选器可以处理的上下文类型。 开发上下文功能筛选器时,可以通过指定上下文类型来建立使用筛选器的要求。

由于每个类型都是类的 Object 后代,因此可为任何提供的上下文调用实现的 IContextualFeatureFilter<object> 筛选器。 下面的代码提供了特定上下文功能筛选器的示例。 在此代码中,如果帐户位于已启用的帐户的已配置列表中,则会启用一项功能。

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

[FilterAlias("AccountId")]
class AccountIdFilter : IContextualFeatureFilter<IAccountContext>
{
    public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext featureEvaluationContext, IAccountContext accountId)
    {
        //
        // Evaluate whether the feature should be on by using the IAccountContext that's provided.
    }
}

AccountIdFilter 类需要提供一个实现了 IAccountContext 的对象以便评估某特征的状态。 使用此功能筛选器时,调用方需要确保传入的对象实现 IAccountContext

注意

单个类型只能实现一个功能筛选器接口。 尝试添加一个实现多个特性筛选器接口的特性筛选器会导致异常 ArgumentException

在使用相同别名时,应用上下文和非上下文筛选器

实现IFeatureFilterIContextualFeatureFilter的筛选器可以共享同一别名。 具体而言,您可以拥有一个筛选器别名,由至多一个IFeatureFilter实现共享,如果对于ContextType有一个适用的筛选器,并且在此情况下可以由零或IContextualFeatureFilter<ContextType>个实现共享。

若要了解在应用程序中注册相同名称的上下文和非上下文筛选器时选择筛选器的过程,请考虑以下示例。

三个筛选器共享 SharedFilterName 别名。

  • 名为FilterA的非上下文筛选器
  • 可以接受TypeB类型上下文的FilterB上下文筛选器。
  • 接受 TypeC 上下文的名为 FilterC 的上下文筛选器

在其配置中,名为MyFeature的功能标志使用SharedFilterName功能筛选器。

如果注册了所有三个筛选器:

  • 调用 IsEnabledAsync("MyFeature")时,筛选器 FilterA 用于评估功能标志。
  • 呼叫 IsEnabledAsync("MyFeature", context)时:
    • 如果 context 的类型为 TypeB,则使用 FilterB
    • 如果 context 的类型是 TypeC,则使用 FilterC
    • 如果 context 的类型是 TypeF,则使用 FilterA

内置功能筛选器

有一些功能筛选器随 Microsoft.FeatureManagement 包提供:PercentageFilterTimeWindowFilterContextualTargetingFilterTargetingFilter。 除TargetingFilter之外,使用AddFeatureManagement方法注册功能管理时会自动添加所有筛选器。 使用 WithTargeting 方法添加 TargetingFilter。 有关详细信息,请参阅本文后面的 目标

每个内置功能筛选器都有自己的参数。 以下部分介绍了这些功能筛选器并提供示例。

Microsoft.Percentage

Microsoft.Percentage 筛选器提供了一种基于设置百分比启用功能的方法。

{
    "id": "EnhancedPipeline",
    "enabled": true,
    "conditions": {
        "client_filters": [
            {
                "name": "Microsoft.Percentage",
                "parameters": {
                    "Value": 50
                }
            }
        ]
    }
}

Microsoft.TimeWindow

Microsoft.TimeWindow 筛选器提供了一种基于时间窗口启用功能的方法。

  • 如果您仅指定一个 End 值,则该功能被视为开启直到该时间。
  • 如果仅指定一个 Start 值,则在该时间后的所有时间点,功能将被视为开启。
{
    "id": "EnhancedPipeline",
    "enabled": true,
    "conditions": {
        "client_filters": [
            {
                "name": "Microsoft.TimeWindow",
                "parameters": {
                    "Start": "Sun, 01 Jun 2025 13:59:59 GMT",
                    "End": "Fri, 01 Aug 2025 00:00:00 GMT"
                }
            }
        ]
    }
}

可以将筛选器配置为定期应用时间窗口。 在一天中或一周的特定日子里,如果需要在低流量或高流量时段启用某个功能,此功能非常有用。 若要将单个时间范围扩展到定期时间窗口,请使用参数 Recurrence 来指定重复规则。

注意

若要使用重复周期,必须指定 StartEnd 值。 在重复情况下,End值的日期部分不会指定用于判断筛选器是否仍然有效的结束日期。 相反,筛选器使用相对于开始日期的结束日期来定义递归的时间窗口的持续时间。

{
    "id": "EnhancedPipeline",
    "enabled": true,
    "conditions": {
        "client_filters": [
            {
                "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

    每天的重复模式会导致时间窗口根据每次发生之间指定的天数来重复。

    properties 相关性 说明
    Type 必须 重复模式类型。 必须设置为 Daily
    Interval 可选 每次发生之间的天数。 默认值为 1
  • Weekly

    每周重复模式会导致时间窗口在一周中的同一天或几天重复。 但是,您可以指定每组发生情况之间的周数。

    properties 相关性 说明
    Type 必须 重复模式类型。 必须设置为 Weekly
    DaysOfWeek 必须 事件发生在一周中的天数。
    Interval 可选 每组事件之间的周数。 默认值为 1
    FirstDayOfWeek 可选 作为一周第一天使用的日期。 默认值为 Sunday

    以下示例每隔一周的星期一和星期二重复一次时间窗口:

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

注意

该值 Start 必须是符合重复模式的第一次有效出现。 此外,时间窗口的持续时间不能超过时间窗口的发生频率。 例如,一个 25 小时的时间段无法每天重复。

重复周期范围

有三种可能的重复范围类型: NoEndEndDateNumbered

  • NoEnd

    NoEnd 范围会导致重复执行无限期地发生。

    properties 相关性 说明
    Type 必须 重复范围类型。 必须设置为 NoEnd
  • EndDate

    EndDate 范围会导致时间窗口在符合适用模式的所有日期发生,直到结束日期为止。

    properties 相关性 说明
    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 范围导致时间窗口出现指定的次数。

    properties 相关性 说明
    Type 必须 重复范围类型。 必须设置为 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

Microsoft.Targeting 筛选器提供了一种为目标受众启用功能的方法。 有关目标的深入说明,请参阅本文后面的“目标”。

筛选器参数包括一个描述谁有权访问该功能的Audience对象。 在对象中 Audience ,可以指定用户、组、排除的用户和组,以及用户群的默认百分比。

对于在 Groups 节中列出的每个组对象,还必须指定组成员应具有访问权限的百分比。

对于每个用户,将按以下方式评估该功能:

  • 如果用户被排除,则为用户禁用该功能。 你可以通过以下方式排除用户:

    • Users节中Exclusion列出其名称。
    • 列出他们在 Groups 下属于 Exclusion 部分的组。
  • 如果未排除用户,则满足以下任一条件时,将启用该功能:

    • 该用户列在 Users 节中。
    • 用户被纳入任何组推出百分比中。
    • 用户在默认推出百分比范围内。
  • 如果上述情况均不适用,则为用户禁用该功能。 例如,如果用户不在包含的百分比中,则禁用该功能。

{
    "id": "EnhancedPipeline",
    "enabled": true,
    "conditions": {
        "client_filters": [
            {
                "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。 或者,可以引用最后一段,例如 Percentage

目标设定

目标是一种功能管理策略,可用于逐步向用户群推出新功能。 该策略建立在面向一组称为目标受众的用户的概念之上。 受众由特定用户、组、排除的用户和组,以及整个用户群中的指定百分比组成。 受众中包含的组可以进一步细分为其成员总数的百分比。

以下步骤演示了名为 Beta 的新功能的渐进式推出示例:

  1. 个人用户 Jeff 和 Alicia 有权访问 Beta 功能。
  2. 另一位用户 Mark 请求加入并被接纳。
  3. Ring1 组中的 20% 用户包含在 Beta 功能中。
  4. 包含的 Ring1 用户数被提升到 100%。
  5. 在 Beta 功能中,包含了 5% 的用户群。
  6. 推出百分比将提升至 100%,以完全推出该功能。

该库支持通过内置 Microsoft.Targeting 功能筛选器推出功能的策略。

在 Web 应用程序中进行目标定位

有关使用目标功能筛选器的 Web 应用程序的示例,请参阅 FeatureFlagDemo 示例项目。

若要开始在应用程序中使用 TargetingFilter ,必须将它添加到应用程序的服务集合中,就像任何其他功能筛选器一样。 与其他内置筛选器不同, TargetingFilter 依赖于要添加到应用程序服务集合中的另一个服务。 该服务是ITargetingContextAccessor的一次实现。

Microsoft.FeatureManagement.AspNetCore库提供从请求值中提取目标信息ITargetingContextAccessorHttpContext。 当使用非泛型 WithTargeting 重载 IFeatureManagementBuilder进行定位设置时,可以使用默认的定位上下文访问器。

若要注册默认目标上下文访问器和TargetingFilter,请在IFeatureManagementBuilder上调用WithTargeting

services.AddFeatureManagement()
        .WithTargeting();

还可以通过调用 ITargetingContextAccessorTargetingFilterWithTargeting<T> 来注册自定义实现。 以下代码在 Web 应用程序中设置功能管理,以用于TargetingFilter调用ITargetingContextAccessorExampleTargetingContextAccessor实现。

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

ITargetingContextAccessor

若要在 Web 应用程序中使用 TargetingFilter ,需要实现 ITargetingContextAccessor 。 此要求背后的原因在于,目标评估需要上下文信息(如有关用户的信息)。 此信息存储在类的实例中 TargetingContext 。 不同的应用程序从不同的位置(例如请求的 HTTP 上下文或数据库)中提取此信息。

有关从应用程序的 HTTP 上下文中提取目标上下文信息的示例,请参阅 DefaultHttpTargetingContextAccessorMicrosoft.FeatureManagement.AspNetCore 中。 它提取以下信息:

  • HttpContext.User 属性提取信息
  • UserId 字段中的Identity.Name信息
  • Groups 类型声明中的信息 Role

此实现依赖于使用 IHttpContextAccessor。 有关IHttpContextAccessor的详细信息,请参阅本文前面的“使用 HttpContext”

控制台应用程序中的目标

目标筛选器依赖于目标上下文来评估是否应启用某项功能。 此目标上下文包含要评估的用户和用户所属的组等信息。 在控制台应用程序中,通常没有环境上下文可用于将此信息传递给目标筛选器。 因此,你必须在调用FeatureManager.IsEnabledAsync时直接传递它。 使用 ContextualTargetingFilter 支持这种类型的上下文。 需要将目标上下文发送到功能管理器的应用程序应使用 ContextualTargetingFilter ,而不是 TargetingFilter.

因为ContextualTargetingFilter的实现是IContextualTargetingFilter<ITargetingContext>,您必须向IVariantFeatureManager.IsEnabledAsync传递ITargetingContext的实现,以便能够评估并启用功能。

IVariantFeatureManager fm;
…
// The userId and groups variables are defined earlier in the application.
TargetingContext targetingContext = new TargetingContext
{
   UserId = userId,
   Groups = groups
};

await fm.IsEnabledAsync(featureName, targetingContext);

ContextualTargetingFilter 使用功能筛选器别名 Microsoft.Targeting,因此此筛选器的配置与本文前面的 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 测试提供了一个用于决定设计的常见解决方案。 A/B 测试涉及向用户群的不同段提供不同版本的功能,然后根据用户交互选择版本。 在 .NET 功能管理库中,可以使用变体来表示功能的各种配置来实现 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; }
}

检索变体

对于每个特性,可以使用IVariantFeatureManager接口的方法GetVariantAsync获取变体。

…
IVariantFeatureManager featureManager;
…
Variant variant = await featureManager.GetVariantAsync("MyVariantFeatureFlag", 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,可以从中自动检索。

变种功能标志声明

与标准功能标志相比,变体功能标志具有两个额外的属性: variantsallocation。 该 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"
                    } 
                ]
            }
        ]
    }
}

定义变体

每个变体都有两个属性:名称和配置。 名称用于引用特定变体,而配置则是该变体的值。 可以使用该 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 设置具有以下属性:

properties 说明
default_when_disabled 在功能被视为禁用时请求变体时要使用的变体。
default_when_enabled 当功能已启用且未分配其他变体给用户时,请求变体时使用的变体。
user 一个变体和一个用户列表,以分配此变体给用户。
group 变体和组列表。 如果当前用户至少位于其中一个组,则会分配变体。
percentile 一个版本及其百分比范围,用户所计算的百分比必须符合该范围,以便该版本的分配。
seed 用于计算 percentile 的百分比所依据的值。 如果使用相同的seed值,特定用户的百分比计算在所有功能中都是相同的。 如果未 seed 指定任何值,则会根据功能名称创建默认种子。

如果未启用某个功能,功能管理器将为当前用户分配指定的 default_when_disabled 变体。 在前面的示例中,该功能称为 Small

如果已启用该功能,则功能管理器将按该顺序检查 usergrouppercentile 分配,以分配变体。 在前面的示例中,指定的变体 Big在以下情况下分配给用户:

  • 正在评估的用户名为Marsha
  • 用户位于 Ring1 组中。
  • 用户恰好在第 0 到第 10 个百分位之间。

如果这些分配都不匹配,则将变体 default_when_enabled 分配给用户。 在此示例中,该变体为 Small.

分配逻辑类似于用于 Microsoft.Targeting 功能筛选器的逻辑。 但是,定位中存在一些不在分配中的参数,分配中也有一些不在定位中的参数。 目标和分配的结果不相关。

注意

若要分配功能变体,需要通过调用WithTargeting<T>方法来注册ITargetingContextAccessor

使用变体覆盖启用状态

可以使用变体来替代功能标志的已启用状态。 利用此功能时,可以扩展功能标志的评估。 在调用 IsEnabledAsync 时,如果标志具有变体,功能管理器会检查分配给当前用户的变体是否已配置为覆盖结果。

可以使用可选变量属性 status_override实现重写。 此属性可以具有以下值:

  • None:变体不会影响标志是被视为已启用还是禁用。 默认值为 None
  • Enabled:选择变体后,功能标志将评估为已启用。
  • Disabled:选择变体后,功能标志将评估为已禁用。

不能使用 的状态为 来覆盖功能。

如果将功能标志与二进制变体一起使用,则 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
  • 已为该功能分配的变体。

通过调用 IFeatureManagementBuilder.WithVariantService<T>(string featureName),将 IVariantServiceProvider<T> 的实现提供给应用程序,如以下示例所示。 该代码中的调用将 IVariantServiceProvider<IAlgorithm> 添加到服务集合中。

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

必须通过诸如services.AddSingleton<IAlgorithm, SomeImplementation>()之类的添加方法分别添加每个实现IAlgorithmIAlgorithmIVariantServiceProvider实现取决于ForecastAlgorithm变体功能标志的用途。 如果未将任何 IAlgorithm 实现添加到服务集合,则 IVariantServiceProvider<IAlgorithm>.GetServiceAsync() 返回一个具有 null 结果的任务。

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

变体服务别名属性

变体服务提供程序使用实现的类型名称来匹配分配的变体。 如果使用变体服务修饰 VariantServiceAliasAttribute,则应在配置中使用此属性中声明的名称来引用此变体服务。

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

遥测

部署功能标志更改时,分析其对应用程序的影响通常很重要。 例如,可能会出现以下几个问题:

  • 标志是否按预期启用和禁用?
  • 目标用户是否按预期获得对特定功能的访问权限?
  • 特定用户看到的是哪个变体?

功能标志评估事件的排放和分析可以帮助你回答这些类型的问题。 .NET 功能管理库使用 System.Diagnostics.Activity API 在功能标志评估期间生成跟踪遥测数据。

启用遥测

默认情况下,功能标志不发出遥测。 若要发布给定功能标志的遥测数据,该标志 必须 声明它已启用遥测排放。

对于在 appsettings.json 中定义的功能标志,可以使用 telemetry 属性启用遥测。

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

appsettings.json 文件中的上述代码定义为遥测启用的功能标志MyFeatureFlag。 遥测状态由 telemetryenabledtrue 的指示来表示。 enabled 属性的值必须为 true 才能发布标志的遥测。

功能标志的 telemetry 部分具有以下属性:

properties 说明
enabled 一个布尔值,该值指定是否应为功能标志发布遥测数据。
metadata 键值对的集合(建模为字典),可用于将有关功能标志的自定义元数据附加到评估事件。

自定义遥测发布

功能管理器有一个名为Microsoft.FeatureManagementActivitySource实例。 如果为功能标志启用了遥测:

  • 当特性标志评估启动时,功能管理器将启动一个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。 该 Microsoft.FeatureManagement.Telemetry.ApplicationInsights 包还提供遥测初始值设定项,该初始值设定项会自动标记 TargetingId 所有事件,以便可以将事件链接到标志评估。 若要利用此功能,请添加对包的引用并注册 Application Insights 遥测。 以下代码提供了一个示例:

builder.services
    .AddFeatureManagement()
    .AddApplicationInsightsTelemetry();

注意

为了帮助确保 Application Insights 遥测按预期工作,应使用该 TargetingHttpContextMiddleware 类。

若要在当前活动中启用目标上下文的持久性,可以使用该 TargetingHttpContextMiddleware 类。

app.UseMiddleware<TargetingHttpContextMiddleware>();

有关其用法的示例,请参阅 VariantAndTelemetryDemo 示例。

先决条件

包提供的遥测发布程序 Microsoft.FeatureManagement.Telemetry.ApplicationInsights 需要配置 Application Insights 并将其注册为应用服务。 有关示例代码,请参阅 VariantAndTelemetryDemo 示例应用程序。

缓存

功能状态由 IConfiguration 系统提供。 配置提供程序应处理任何缓存和动态更新。 每当功能管理器评估是否启用某个功能时,功能管理器都会请求 IConfiguration 功能状态的最新值。

快照

某些方案要求功能的状态在请求的生存期内保持一致。 如果IVariantFeatureManager从标准IConfiguration实现返回的值在请求过程中拉取的数据源被更新,则这些值可能会更改。

您可以通过使用 IVariantFeatureManagerSnapshot 来阻止这种行为。 可以采用与IVariantFeatureManager相同的方式IVariantFeatureManagerSnapshot进行检索。 IVariantFeatureManagerSnapshot IVariantFeatureManager实现接口,但在IVariantFeatureManagerSnapshot请求期间缓存功能的第一个评估状态。 它在功能的生存期内返回该状态。

自定义功能提供者

实现自定义功能提供程序时,可以从数据库或功能管理服务等源拉取功能标志。 默认功能提供程序从 .NET Core 配置系统拉取功能标志。 此系统支持在 appsettings.json 文件或配置提供程序(如 Azure 应用配置)中定义功能。 可以自定义此行为,以控制从何处读取功能定义。

若要自定义功能定义的加载,必须实现 IFeatureDefinitionProvider 接口。

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

    IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync();
}

若要使用 的 IFeatureDefinitionProvider实现,必须先将其添加到服务集合中,然后才能添加功能管理。 以下示例添加名为 IFeatureDefinitionProviderInMemoryFeatureDefinitionProvider 实现。

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

后续步骤

若要了解如何在应用程序中使用功能标志,请参阅以下快速入门:

若要了解如何使用功能筛选器,请参阅以下教程: