
Web服务开发过程中我们经常有这样的需求:
这就是功能开关。
日常开发中功能开关我们一般是写到配置文件里的,根据不同的配置,做不同的逻辑;但,其实.net core是对功能开关有官方支持的,但因为跟Azure集成比较好所以文档不在.net core的文档里面,而是在Azure的文档这边:
https://docs.microsoft.com/en-us/azure/azure-app-configuration/
Asp.net Core的功能开关(Feature Flag)是直接仅根据配置文件方式使用,和集成Azure配置中心使用的;我们来看看区别;
install-package Microsoft.FeatureManagement.AspNetCorebuilder.Services.AddFeatureManagement();appsettings.json
"FeatureManagement": { //简单功能开关 "Beta": true, "v1": true, "v2": true, }以上配置对应以下的枚举:
public enum MyFeatureFlags { Beta, V1, V2, PercentageFlag, TimeWindowFlag, CustomFeatureFlag }其实不用枚举,直接用字符串也是可以的;
1、创建一个FeatureFlagController;
注入服务:
private readonly IFeatureManager _featureManager;public FeatureFlagController(IFeatureManager featureManager){ _featureManager = featureManager;}/// <summary>/// 当启用beta版本的时候接口有效/// </summary>/// <returns></returns>[FeatureGate(MyFeatureFlags.Beta)][HttpGet]public async Task<IActionResult> Beta(){ var beta = await _featureManager.IsEnabledAsync(nameof(MyFeatureFlags.Beta)); if (beta) { //beta版本特有逻辑 } return Success("Beta", beta); //这里Success是封装的,大家可以改成返回Ok()}/// <summary>/// 当启用v1版本的时候接口有效/// </summary>/// <returns></returns>[FeatureGate(MyFeatureFlags.V1)][HttpGet]public async Task<IActionResult> V1(){ return Success("V1");}/// <summary>/// 当启用v2版本的时候接口有效/// </summary>/// <returns></returns>[FeatureGate(MyFeatureFlags.V2)][HttpGet]public async Task<IActionResult> V2(){ return Success("V2");}由于我们上面的配置都是开启的:
...//简单功能开关"Beta": true,"v1": true,"v2": true,可以看到:

接口都可以访问,我们把v1改成false试试:

马上404了,这里清晰的看到,功能开关在多版本Api上线下某个版本时候确实方便;
基于过滤器的功能开关是有一定逻辑的功能开关;
/// <summary>/// 启用百分率的功能开关/// </summary>/// <returns></returns>[FeatureGate(MyFeatureFlags.PercentageFlag)][HttpGet]public async Task<IActionResult> PercentageFlag(){ return Success("PercentageFlag");}builder.Services.AddFeatureManagement() .AddFeatureFilter<PercentageFilter>();添加配置:
FeatureManagement节点下:
//百分率功能开关"PercentageFlag": { "EnabledFor": [ { "Name": "Percentage", "Parameters": { "Value": 30 } } ]},这里的配置参数值代表30%的概率启用次功能,我们试试:

分别是不启用,和启用状态;
/// <summary>/// 启用时间窗口的功能开关/// </summary>/// <returns></returns>[FeatureGate(MyFeatureFlags.TimeWindowFlag)][HttpGet]public async Task<IActionResult> TimeWindowFlag(){ return Success("TimeWindowFlag");}builder.Services.AddFeatureManagement() .AddFeatureFilter<TimeWindowFilter>();添加配置:
//时间窗口功能开关"TimeWindowFlag": { "EnabledFor": [ { "Name": "TimeWindow", "Parameters": { "Start": "2022/08/03 08:00:00 +00:00", //这里是UTC时间 "End": "2022/08/03 09:00:00 +00:00" } } ]},这个开关在2022年8月3日 下午16时(北京时间)和17时这个世界窗口内才启用;对应的:
Start:就是生效时刻;
End:失效时刻;
ok,以上都是系统内置的功能开关,我们来根据自己需求创建一个自定义的;
需求:某个功能只有在客户端是手机或者平板的情况下启用,pc端不启用;
创建一个自定义功能开关过滤器类CustomFeatureFilter
[FilterAlias("CustomFeature")]public class CustomFeatureFilter : IFeatureFilter{ private readonly IHttpContextAccessor _httpContextAccessor; public CustomFeatureFilter(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context) { //这里参数模拟平台,实际业务会有实际业务的逻辑 var platform = _httpContextAccessor.HttpContext.Request.Query["platform"].ToString(); var allowPlatform = context.Parameters.Get<CustomFeatureFilterSettings>(); return Task.FromResult(allowPlatform.AllowedPlatforms.Any(c => c == platform)); }}public class CustomFeatureFilterSettings{ public string[] AllowedPlatforms { get; set; }}/// <summary>/// 自定义功能开关/// </summary>/// <returns></returns>[FeatureGate(MyFeatureFlags.CustomFeatureFlag)][HttpGet]public async Task<IActionResult> CustomFeatureFlag(string platform){ return Success("CustomFeatureFlag");}builder.Services.AddFeatureManagement() .AddFeatureFilter<CustomFeatureFilter>();添加配置:
//自定义功能开关"CustomFeatureFlag": { "EnabledFor": [ { "Name": "CustomFeature", "Parameters": { "AllowedPlatforms": [ //这里配置运行启用功能的平台 "phone", "pad" //"pc" ] } } ]}我们来测测:

可以看到仅在设置运行的平台下启用,验证ok;
"ConnectionStrings": { "AppConfig": "<your app connection string>" },具体可参考我之前的文章:《微软Azure配置中心 App Configuration (一):轻松集成到Asp.Net Core》
var connectionString = builder.Configuration.GetConnectionString("AppConfig");builder.Host.ConfigureAppConfiguration((hostingContext, config) =>{ //配置不同功能 config.AddAzureAppConfiguration(options => { ////启用功能开关特性 options.Connect(connectionString) //启用功能开关特性 .UseFeatureFlags(options => { options.CacheExpirationInterval = TimeSpan.FromSeconds(30); //配置FeatureFlag缓存本地时间(默认就是30) }); });});UseFeatureFlags启用后,本地配置文件的方式失效;
builder.Services.AddAzureAppConfiguration(); //注入服务创建配置:

填写配置信息:

OK,以上是基本的配置,配置好后可以直接在列表页面勾选启用配置与否:

百分率功能开关

时间窗口功能开关

这里的Start date,和Expiry date,就对应前面配置文件的Start,End;
自定义功能开关

这里的过滤器的Name:CustomFeature ,要跟代码标签 [FilterAlias("CustomFeature")]一致;
AllowedPlatforms:也要跟代码里面的配置一致,["phone","pad"]这个是数组的写法;
1、启用集成到Azure的UseFeatureFlags后,本地配置文件的方式失效;
2、Azure这套功能开关还是有可选之处的,我尤其喜欢其接口标签[FeatureGate];
另外定义了的标准配置项,与Azure配置中心无缝集成,香。
https://github.com/gebiWangshushu/Hei.Azure.Test
https://docs.microsoft.com/en-us/azure/azure-app-configuration/overview