实现一个基于 IConfiguration 的低配版 FeatureFlag
Intro
在我们的应用中,可能有一些配置开关的需求,某些功能是否启用使用一个配置开关,用的时候就打开,不用的时候就关掉,于是基于 .NET Core 的里配置体系写了一个简单的 FeatureFlag,类似于之前的 AppSetting 的扩展 给 IConfiguration 写一个 GetAppSetting 扩展方法
Sample
首先来看一个实现效果:
[HttpGet("[action]")]
[FeatureFlagFilter("Flag1", DefaultValue = true)]
public IActionResult FeatureEnableTest()
{return Ok(new{Time = DateTime.UtcNow});
}[HttpGet("[action]")]
[FeatureFlagFilter("Flag2", DefaultValue = false)]
public IActionResult FeatureDisableTest()
{return Ok(new{Time = DateTime.UtcNow});
}
这是两个完全一样的 API,为了测试 featureFilter 的功能
启用的 API 效果就是可以正常访问:
禁用的效果,默认是返回一个 404,如果需要也可以自定义,只需要实现一个接口,注入进去即可
Implement
实现代码其实也比较简单,分为两部分,一部分是 IConfiguration
的扩展,从配置中获取某个配置开关的值,另外一部分则是 ASP.NET Core 相关的扩展,上面的示例是一个 MVC Filter 的一个示例,比较简单所以我们就直接看代码
IConfiguration
扩展实现代码如下:
public static string FeatureFlagsSectionName = "FeatureFlags";public static bool TryGetFeatureFlagValue(this IConfiguration configuration, string featureFlagName, out bool featureFlagValue)
{featureFlagValue = false;var section = configuration.GetSection(FeatureFlagsSectionName);if (section.Exists()){return bool.TryParse(section[featureFlagName], out featureFlagValue);}return false;
}public static bool IsFeatureEnabled(this IConfiguration configuration, string featureFlagName, bool defaultValue = false)
{if (TryGetFeatureFlagValue(configuration, featureFlagName, out var value)){return value;}return defaultValue;
}
上面示例中的 FeatureFlagFilter
是一个 MVC 的 ResourceFilter
,实现代码如下:
public interface IFeatureFlagFilterResponseFactory
{public Task<IActionResult> GetResponse(ResourceExecutingContext resourceExecutingContext);
}[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class FeatureFlagFilterAttribute : Attribute, IAsyncResourceFilter
{public bool DefaultValue { get; set; }public string FeatureFlagName { get; }public FeatureFlagFilterAttribute(string featureFlagName){FeatureFlagName = featureFlagName ?? throw new ArgumentNullException(nameof(featureFlagName));}public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next){var configuration = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>();if (configuration.IsFeatureEnabled(FeatureFlagName, DefaultValue)){await next();}else{var responseFactory = context.HttpContext.RequestServices.GetService<IFeatureFlagFilterResponseFactory>();if (responseFactory != null){context.Result = await responseFactory.GetResponse(context);}else{context.Result = new NotFoundResult();}}}
}
More
关于 FeatherFlag,上面只是一个简单的封装,微软有一个功能更为丰富的库来支持 Microsoft.FeatureManagement.AspNetCore, 源代码在 Github 上有需要的可以参考 https://github.com/microsoft/FeatureManagement-Dotnet
以上示例代码可以从 Github 获取:https://github.com/WeihanLi/WeihanLi.Web.Extensions/blob/dev/samples/WeihanLi.Web.Extensions.Samples/ValuesController.cs
References
https://github.com/WeihanLi/WeihanLi.Web.Extensions/blob/dev/samples/WeihanLi.Web.Extensions.Samples/ValuesController.cs
https://github.com/WeihanLi/WeihanLi.Web.Extensions/blob/dev/src/WeihanLi.Web.Extensions/Middleware/FeaturedMiddleware.cs
https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Extensions/ConfigurationExtension.cs#L131
https://github.com/microsoft/FeatureManagement-Dotnet
https://www.nuget.org/packages/Microsoft.FeatureManagement.AspNetCore/