.NET 应用如何优雅的做功能开关(Feature Flag)
點擊上方藍字關注“汪宇杰博客”
導語
曾經,我們要在應用程序里做功能開關,就避免不了在配置文件里加上一堆 bool 類型的配置項,然后在代碼里用 if else 去判斷。盡管這種做法是可行的,但我們現在有辦法讓代碼更加整潔,避免成堆的 if else 出現。
.NET 功能管理庫
微軟為了解決常見的功能開關問題場景,推出了 .NET Core Feature Management 庫。它由 Azure 團隊發布,并屬于 Azure 文檔的一部分,但我發現就算在沒有 Azure 環境的情況下,它依然可以正常全功能運行!
Azure 在此的作用僅僅是用 Azure App Configuration 作為功能開關的數據源,而我們完全可以用本地的 appsettings.json 來替代,避免了購買 Azure 從而落魄街頭的風險。
安裝功能管理庫
以我的博客系統為例,我的應用是 ASP.NET MVC / Web API類型的,我需要添加的包為?Microsoft.FeatureManagement.AspNetCore。如果你的應用并非ASP.NET,可以只添加?Microsoft.FeatureManagement
<PackageReference Include="Microsoft.FeatureManagement" Version="2.2.0" />
然后注冊到 DI 里去
using Microsoft.FeatureManagement;
public class Startup
{
? ? public void ConfigureServices(IServiceCollection services)
? ? {
? ? ? ? services.AddFeatureManagement();
? ? }
}
添加功能開關配置項
以我的博客系統為例,原先我在 AppSettings p 中有兩個bool類型的配置項,現在就可以遷移到名為?FeatureManagement 的新 p 里。
相對應的,在 C# 代碼里,去掉原來的項,添加一個新的枚舉類型,值的名稱對應配置項的名稱。
這個枚舉類型不是必須的,但非常建議創建枚舉,這是為了保證在使用功能開關的時候有強類型支持,避免用string導致哪里名字沒改對造成996。
使用功能開關
我們只需從DI里拿到 IFeatureManager 的實例,即可判斷功能開關是否打開。例如:
IFeatureManager featureManager;
...
if (await featureManager.IsEnabledAsync(nameof(MyFeatureFlags.FeatureA)))
{
? ? // 執行代碼
}
在 ASP.NET 項目里,最方便的就是通過構造函數獲取?IFeatureManager 的實例
public class HomeController : Controller
{
? ? private readonly IFeatureManager _featureManager;
? ? public HomeController(IFeatureManager featureManager)
? ? {
? ? ? ? _featureManager = featureManager;
? ? }
}
那么問題來了,說好的少寫 if else 呢?這個 IsEnabledAsync 不還是得寫 if?
其實 Microsoft.FeatureManagement.AspNetCore 這個包包括了 MVC / Web API 項目所需要用到的許多助手功能。可以讓我們避免大量的 if else。
在 Controller 級別添加功能開關
還是以我博客系統為例,我的 GraphController 只有在 EnableWebApi 開關打開的時候才響應用戶請求,那么本來的 if else 判斷現在就可以:
[FeatureGate(FeatureFlags.EnableWebApi)]
// ...?
public class GraphController : ControllerBase?
{
// ...
}
是不是很爽?
在 Action 級別添加功能開關
[FeatureGate(FeatureFlags.EnableAudit)]
public async Task<IActionResult> ClearAuditLogs()
{
? ? // ...
}
在 View 上添加功能開關
先在?_ViewImports.cshtml 中添加 taghelper 聲明。
@addTagHelper *, Microsoft.FeatureManagement.AspNetCore
然后就可以用?<feature> 標簽選擇性的渲染 HTML 內容了!
<feature name="FeatureA">
? ? <p>This can only be seen if 'FeatureA' is enabled.</p>
</feature>
對于feature關閉才顯示的內容,加個 negate 就好了
<feature name="FeatureA" negate="true">
? ? <p>This will be shown if 'FeatureA' is disabled.</p>
</feature>
還可用? All, Any 屬性控制多個功能開關的顯示處理。All 表示列出的功能得全啟用才執行,Any 表示列出的功能里任意一個為 true 就可以執行。
<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>
根據功能開關添加 Filter
使用?AddForFeature() 拓展方法
using Microsoft.FeatureManagement.FeatureFilters;
IConfiguration Configuration { get; set;}
public void ConfigureServices(IServiceCollection services)
{
? ? services.AddMvc(options => {
? ? ? ? options.Filters.AddForFeature<SomeMvcFilter>(nameof(MyFeatureFlags.FeatureA));
? ? });
}
根據功能開關添加 Middleware
app.UseMiddlewareForFeature<ThirdPartyMiddleware>(nameof(MyFeatureFlags.FeatureA));
或者
app.UseForFeature(featureName, appBuilder => {
? ? appBuilder.UseMiddleware<T>();
});
小提示
功能開關的配置值更改,無需重啟應用程序,修改配置文件后可以熱更新,立即生效!
另外,如果你足夠有錢,也推薦試試 Azure App Configuration,將你的應用功能開關放在云端統一管理,可以非常方便的針對用戶群體配置 A/B,藍綠測試哦!
參考文檔:https://docs.microsoft.com/en-us/azure/azure-app-configuration/use-feature-flags-dotnet-core?WT.mc_id=AZ-MVP-5002809
汪宇杰博客
Azure | .NET |?微軟 MVP
無廣告,不賣課,做純粹的技術公眾號
喜歡本篇內容請點個在看
總結
以上是生活随笔為你收集整理的.NET 应用如何优雅的做功能开关(Feature Flag)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何踢掉 sql 语句中的尾巴,我用 C
- 下一篇: 使用BeetleX访问redis服务