教程:在 ASP.NET Core 应用中使用功能标志Tutorial: Use feature flags in an ASP.NET Core app

.NET Core 功能管理库能够顺畅地支持在 .NET 或 ASP.NET Core 应用程序中实施功能标志。The .NET Core Feature Management libraries provide idiomatic support for implementing feature flags in a .NET or ASP.NET Core application. 使用这些库能够以声明方式将功能标志添加到代码中,因此不需要手动编写这些功能标志的所有 if 语句。These libraries allow you to declaratively add feature flags to your code so that you don't have to write all the if statements for them manually.

功能管理库还会在幕后管理功能标志生命周期。The Feature Management libraries also manage feature flag lifecycles behind the scenes. 例如,这些库可刷新和缓存标志状态,或者保证标志状态在请求调用期间保持不变。For example, the libraries refresh and cache flag states, or guarantee a flag state to be immutable during a request call. 此外,ASP.NET Core 库提供现成的集成,包括 MVC 控制器操作、视图、路由和中间件。In addition, the ASP.NET Core library offers out-of-the-box integrations, including MVC controller actions, views, routes, and middleware.

将功能标志添加到 ASP.NET Core 应用快速入门介绍了在 ASP.NET Core 应用程序中添加功能标志的多种方法。The Add feature flags to an ASP.NET Core app Quickstart shows several ways to add feature flags in an ASP.NET Core application. 本教程将更详细地介绍这些方法。This tutorial explains these methods in more detail. 有关完整参考信息,请参阅 ASP.NET Core 功能管理文档For a complete reference, see the ASP.NET Core feature management documentation.

在本教程中,您将学习如何执行以下操作:In this tutorial, you will learn how to:

  • 在应用程序的关键组件中添加功能标志,以控制功能可用性。Add feature flags in key parts of your application to control feature availability.
  • 使用应用程序配置来管理功能标志时,与应用程序配置相集成。Integrate with App Configuration when you're using it to manage feature flags.

设置功能管理Set up feature management

添加对 Microsoft.FeatureManagement.AspNetCoreMicrosoft.FeatureManagement NuGet 包的引用以利用 .NET Core 功能管理器。Add a reference to the Microsoft.FeatureManagement.AspNetCore and Microsoft.FeatureManagement NuGet packages to utilize the .NET Core feature manager.

.NET Core 功能管理器 IFeatureManager 从框架的本机配置系统获取功能标志。The .NET Core feature manager IFeatureManager gets feature flags from the framework's native configuration system. 因此,可以使用 .NET Core 支持的任何配置源(包括本地 appsettings.json 文件或环境变量)来定义应用程序的功能标志。As a result, you can define your application's feature flags by using any configuration source that .NET Core supports, including the local appsettings.json file or environment variables. IFeatureManager 依赖于 .NET Core 依赖项注入。IFeatureManager relies on .NET Core dependency injection. 可以使用标准约定来注册功能管理服务。You can register the feature management services by using standard conventions:

using Microsoft.FeatureManagement;

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

默认情况下,功能管理器从 .NET Core 配置数据的 "FeatureManagement" 节检索功能标志。By default, the feature manager retrieves feature flags from the "FeatureManagement" section of the .NET Core configuration data. 以下示例告知功能管理器要从名为 "MyFeatureFlags" 的另一个节读取数据:The following example tells the feature manager to read from a different section called "MyFeatureFlags" instead:

using Microsoft.FeatureManagement;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddFeatureManagement(options =>
        {
                options.UseConfiguration(Configuration.GetSection("MyFeatureFlags"));
        });
    }
}

如果你在功能标志中使用筛选器,则需要包含并注册一个额外的库。If you use filters in your feature flags, you need to include an additional library and register it. 以下示例演示如何使用名为 PercentageFilter 的内置功能筛选器:The following example shows how to use a built-in feature filter called PercentageFilter:

using Microsoft.FeatureManagement;
using Microsoft.FeatureManagement.FeatureFilters;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddFeatureManagement()
                .AddFeatureFilter<PercentageFilter>();
    }
}

我们建议将功能标志保留在应用程序的外部,并单独对其进行管理。We recommend that you keep feature flags outside the application and manage them separately. 这样便可以随时修改标志状态,并使这些更改在应用程序中立即生效。Doing so allows you to modify flag states at any time and have those changes take effect in the application right away. 应用程序配置提供一个中心位置用于通过专用门户 UI 来组织和控制所有功能标志。App Configuration provides a centralized place for organizing and controlling all your feature flags through a dedicated portal UI. 应用程序配置还直接通过其 .NET Core 客户端库将标志传送到应用程序。App Configuration also delivers the flags to your application directly through its .NET Core client libraries.

将 ASP.NET Core 应用程序连接到应用程序配置的最简单方法是使用配置提供程序 Microsoft.Azure.AppConfiguration.AspNetCoreThe easiest way to connect your ASP.NET Core application to App Configuration is through the configuration provider Microsoft.Azure.AppConfiguration.AspNetCore. 按照以下步骤使用此 NuGet 包。Follow these steps to use this NuGet package.

  1. 打开 Program.cs 文件,并添加以下代码。Open Program.cs file and add the following code.

    using Microsoft.Extensions.Configuration.AzureAppConfiguration;
    
    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
               .ConfigureAppConfiguration((hostingContext, config) => {
                   var settings = config.Build();
                   config.AddAzureAppConfiguration(options => {
                       options.Connect(settings["ConnectionStrings:AppConfig"])
                              .UseFeatureFlags();
                    });
               })
               .UseStartup<Startup>();
    
  2. 打开“Startup.cs”并更新 Configure 方法,添加名为 UseAzureAppConfiguration 的内置中间件。Open Startup.cs and update the Configure method to add the built-in middleware called UseAzureAppConfiguration. 此中间件允许在 ASP.NET Core Web 应用继续接收请求的同时定期刷新功能标志值。This middleware allows the feature flag values to be refreshed at a recurring interval while the ASP.NET Core web app continues to receive requests.

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseAzureAppConfiguration();
        app.UseMvc();
    }
    

功能标志值预期会不断变化。Feature flag values are expected to change over time. 默认情况下,功能标志值缓存 30 秒,因此,在中间件收到请求时触发的刷新操作不会更新该值,直到缓存值过期为止。By default, the feature flag values are cached for a period of 30 seconds, so a refresh operation triggered when the middleware receives a request would not update the value until the cached value expires. 以下代码演示如何在 options.UseFeatureFlags() 调用中将缓存过期时间或轮询间隔更改为 5 分钟。The following code shows how to change the cache expiration time or polling interval to 5 minutes in the options.UseFeatureFlags() call.

config.AddAzureAppConfiguration(options => {
    options.Connect(settings["ConnectionStrings:AppConfig"])
           .UseFeatureFlags(featureFlagOptions => {
                featureFlagOptions.CacheExpirationTime = TimeSpan.FromMinutes(5);
           });
});

功能标志声明Feature flag declaration

每个功能标志有两个组成部分:一个名称,以及用于评估功能状态是否为“打开”(即,其值为 True)的一个或多个筛选器的列表。 Each feature flag has two parts: a name and a list of one or more filters that are used to evaluate if a feature's state is on (that is, when its value is True). 筛选器定义有关何时应启用某个功能的用例。A filter defines a use case for when a feature should be turned on.

如果某个功能标志包含多个筛选器,则会按顺序遍历筛选器列表,直到其中一个筛选器确定应启用该功能。When a feature flag has multiple filters, the filter list is traversed in order until one of the filters determines the feature should be enabled. 此时,该功能标志为“打开”,并会跳过所有剩余的筛选器结果。 At that point, the feature flag is on, and any remaining filter results are skipped. 如果没有任何筛选器指示应启用该功能,则表示该功能标志为“关闭”。 If no filter indicates the feature should be enabled, the feature flag is off.

功能管理器支持将 appsettings.json 用作功能标志的配置源。The feature manager supports appsettings.json as a configuration source for feature flags. 以下示例演示如何在 JSON 文件中设置功能标志:The following example shows how to set up feature flags in a JSON file:

"FeatureManagement": {
    "FeatureA": true, // Feature flag set to on
    "FeatureB": false, // Feature flag set to off
    "FeatureC": {
        "EnabledFor": [
            {
                "Name": "Percentage",
                "Parameters": {
                    "Value": 50
                }
            }
        ]
    }
}

按照约定,此 JSON 文档的 FeatureManagement 节用于功能标志设置。By convention, the FeatureManagement section of this JSON document is used for feature flag settings. 以上示例演示了三个功能标志,其筛选器已在 EnabledFor 属性中定义:The prior example shows three feature flags with their filters defined in the EnabledFor property:

  • FeatureA 状态为“打开”。 FeatureA is on.
  • FeatureB 状态为“关闭”。 FeatureB is off.
  • FeatureC 指定包含 Parameters 属性的名为 Percentage 的筛选器。FeatureC specifies a filter named Percentage with a Parameters property. Percentage 是可配置的筛选器。Percentage is a configurable filter. 在此示例中,Percentage 指定打开 FeatureC 标志的概率为 50%。 In this example, Percentage specifies a 50-percent probability for the FeatureC flag to be on.

功能标志引用Feature flag references

若要在代码中轻松引用功能标志,应将其定义为 enum 变量:So that you can easily reference feature flags in code, you should define them as enum variables:

public enum MyFeatureFlags
{
    FeatureA,
    FeatureB,
    FeatureC
}

功能标志检查Feature flag checks

功能管理的基本模式是首先检查功能标志是否设置为“打开”。 The basic pattern of feature management is to first check if a feature flag is set to on. 如果是,则功能管理器将运行该功能包含的操作。If so, the feature manager then runs the actions that the feature contains. 例如:For example:

IFeatureManager featureManager;
...
if (await featureManager.IsEnabledAsync(nameof(MyFeatureFlags.FeatureA)))
{
    // Run the following code
}

依赖项注入Dependency injection

在 ASP.NET Core MVC 中,可以通过依赖项注入访问功能管理器 IFeatureManagerIn ASP.NET Core MVC, you can access the feature manager IFeatureManager through dependency injection:

public class HomeController : Controller
{
    private readonly IFeatureManager _featureManager;

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

控制器操作Controller actions

在 MVC 控制器中,使用 FeatureGate 属性控制是要启用整个控制器类还是特定的操作。In MVC controllers, you use the FeatureGate attribute to control whether a whole controller class or a specific action is enabled. 以下 HomeController 控制器要求 FeatureA 状态为“打开”,才能执行控制器类包含的任何操作: The following HomeController controller requires FeatureA to be on before any action the controller class contains can be executed:

using Microsoft.FeatureManagement.Mvc;

[FeatureGate(MyFeatureFlags.FeatureA)]
public class HomeController : Controller
{
    ...
}

以下 Index 操作要求 FeatureA 状态为“打开”才能运行该操作: The following Index action requires FeatureA to be on before it can run:

using Microsoft.FeatureManagement.Mvc;

[FeatureGate(MyFeatureFlags.FeatureA)]
public IActionResult Index()
{
    return View();
}

当由于控制功能标志状态为“关闭”而阻止了 MVC 控制器或操作时,将调用已注册的 IDisabledFeaturesHandler接口。 When an MVC controller or action is blocked because the controlling feature flag is off, a registered IDisabledFeaturesHandler interface is called. 默认的 IDisabledFeaturesHandler 接口向客户端返回 404 状态代码,但不返回响应正文。The default IDisabledFeaturesHandler interface returns a 404 status code to the client with no response body.

MVC 视图MVC views

打开 Views 目录中的 _ViewImports.cshtml ,并添加功能管理器标记帮助器 :Open _ViewImports.cshtml in the Views directory, and add the feature manager tag helper:

@addTagHelper *, Microsoft.FeatureManagement.AspNetCore

在 MVC 视图中,可以使用 <feature> 标记根据是否启用了某个功能标志来呈现内容:In MVC views, you can use a <feature> tag to render content based on whether a feature flag is enabled:

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

要在不满足要求时显示替代内容,可以使用 negate 属性。To display alternate content when the requirements are not met the negate attribute can be used.

<feature name="FeatureA" negate="true">
    <p>This will be shown if 'FeatureA' is disabled.</p>
</feature>

如果启用了列表中的任何或所有功能,还可以使用 <feature> 功能标记显示内容。The feature <feature> tag can also be used to show content if any or all features in a list are enabled.

<feature name="FeatureA, FeatureB" requirement="All">
    <p>This can only be seen if 'FeatureA' and 'FeatureB' are enabled.</p>
</feature>
<feature name="FeatureA, FeatureB" requirement="Any">
    <p>This can be seen if 'FeatureA', 'FeatureB', or both are enabled.</p>
</feature>

MVC 筛选器MVC filters

可以设置 MVC 筛选器,以根据功能标志的状态激活这些筛选器。You can set up MVC filters so that they're activated based on the state of a feature flag. 以下代码添加名为 SomeMvcFilter 的 MVC 筛选器。The following code adds an MVC filter named SomeMvcFilter. 仅当已启用 FeatureA 时,才会在 MVC 管道内部触发此筛选器。This filter is triggered within the MVC pipeline only if FeatureA is enabled. 此功能仅限于 IAsyncActionFilterThis capability is limited to IAsyncActionFilter.

using Microsoft.FeatureManagement.FeatureFilters;

IConfiguration Configuration { get; set;}

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options => {
        options.Filters.AddForFeature<SomeMvcFilter>(nameof(MyFeatureFlags.FeatureA));
    });
}

中间件Middleware

还可以使用功能标志按条件添加应用程序分支和中间件。You can also use feature flags to conditionally add application branches and middleware. 仅当已启用 FeatureA 时,以下代码才会在请求管道中插入中间件组件。The following code inserts a middleware component in the request pipeline only when FeatureA is enabled:

app.UseMiddlewareForFeature<ThirdPartyMiddleware>(nameof(MyFeatureFlags.FeatureA));

此代码生成更通用的功能来根据功能标志分支整个应用程序。This code builds off the more-generic capability to branch the entire application based on a feature flag:

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

后续步骤Next steps

本教程已介绍如何使用 Microsoft.FeatureManagement 库在 ASP.NET Core 应用程序中实施功能标志。In this tutorial, you learned how to implement feature flags in your ASP.NET Core application by using the Microsoft.FeatureManagement libraries. 有关 ASP.NET Core 和应用程序配置中的功能管理支持的详细信息,请参阅以下资源:For more information about feature management support in ASP.NET Core and App Configuration, see the following resources: