文章目录
- 前言
- 1.功能开关的概念
- 2.功能开关的优点
- 一、ASP.NET Core中间件实现
- 1.相关依赖
- 2.中间件代码
- 3.在管道中的使用
- 4.修改配置控制
- 二、IFeatureFilter过滤器
- 1.过滤去代码
- 2.配置文件
- 3.改写功能开关中间件
前言
1.功能开关的概念
功能开关,相当于可以控制访问的流转和访问的允许和禁止。例如东京在6月18日做店庆促销活动,在交易下单环节,可能需要调用A、B、C三个接口来完成,但是其实A和B是必须的,C只是附加的功能(例如在下单的时候做一下推荐),可有可无,在平时系统没有压力,容量充足的情况下,调用下没问题,但是在类似店庆之类的大促环节,系统已经满负荷了,这时候其实完全可以不去调用C接口,怎么实现这个呢?改代码?no,no,no,这样太不敏捷,此时开关诞生了,开发人员只要简单执行一下命令或者点一下页面,就可以关掉对于C接口的调用,在大促过去之后,再把开关恢复回去即可。
2.功能开关的优点
功能开关(Feature flags)就是这样一种部署技术。
- 可以提高应用程序的灵活性。
- 可以将新功能部署到生产环境中,但限制其可用性。
- 可以为控制是否激活一项新功能,而无需重新启动应用程序或部署新代码,它们将新功能的发布与代码部署分离。
一、ASP.NET Core中间件实现
1.相关依赖
我们需要引用nuget包Microsoft.FeatureManagement.AspNetCore
,并在ConfigureServices中添加扩展
public void ConfigureServices(IServiceCollection services)
{
...
services.AddFeatureManagement();
...
}
setting.json文件增加配置
代码语言:javascript复制"FeatureManagement":
{
"ForbiddenDebugEndpoint": false
}
2.中间件代码
代码语言:javascript复制public class DebugMiddleware : IMiddleware
{
private readonly IFeatureManager _featureManager;
public DebugMiddleware(IFeatureManager featureManager)
{
_featureManager = featureManager;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var isDebugEndpoint = context.Request.Path.Value.Contains("/test");
var debugEndpoint = await _featureManager.IsEnabledAsync("ForbiddenDebugEndpoint");
if (isDebugEndpoint && debugEndpoint)
{
context.SetEndpoint(new Endpoint((context) =>
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
return Task.CompletedTask;
},
EndpointMetadataCollection.Empty,
"无权访问"));
}
await next(context);
}
}
3.在管道中的使用
代码语言:javascript复制app.UseMiddleware<DebugMiddleware >()
4.修改配置控制
关键就是这句话,我们使用了功能开关:
代码语言:javascript复制var debugEndpoint = await _featureManager.IsEnabledAsync("ForbiddenDebugEndpoint");
只需要在配置文件中设置ForbiddenDebugEndpoint
值为true
或false
就可以控制
"FeatureManagement":
{
"ForbiddenDebugEndpoint": false
}
二、IFeatureFilter过滤器
IFeatureFilter(功能过滤器)可用于确定是否满足某些条件以启用一项功能。功能过滤器可以自由使用任何可用的标准,例如流程状态或请求内容。 可以为给定功能注册功能过滤器,如果任何特征过滤器评估为真,该特征将被考虑启用。
1.过滤去代码
代码语言:javascript复制public class DebugFeatureSettings
{
public string[] DebugEndpoints { get; set; }
}
[FilterAlias("DebugFeatureFilter")]
public class DebugFeatureFilter : IFeatureFilter
{
private readonly IHttpContextAccessor _httpContextAccessor;
public DebugFeatureFilter(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
{
var settings = context.Parameters.Get<DebugFeatureSettings>();
foreach (var endPoint in settings.DebugEndpoints)
{
var isDebugEndpoint = _httpContextAccessor.HttpContext.Request.Path.Value.Contains(endPoint);
return Task.FromResult(isDebugEndpoint);
}
return Task.FromResult(false);
}
}
2.配置文件
代码语言:javascript复制"FeatureManagement": {
"ForbiddenDebugEndpoint": {
"EnabledFor": [
{
"Name": "DebugFeatureFilter",
"Parameters": {
"DebugEndpoints": [ "/test" ]
}
}
]
}
}
3.改写功能开关中间件
代码语言:javascript复制public class DebugMiddleware : IMiddleware
{
private readonly IFeatureManager _featureManager;
public DebugMiddleware(IFeatureManager featureManager)
{
_featureManager = featureManager;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var debugEndpoint = await _featureManager.IsEnabledAsync("ForbiddenDebugEndpoint");
if (debugEndpoint)
{
context.SetEndpoint(new Endpoint((context) =>
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
return Task.CompletedTask;
},
EndpointMetadataCollection.Empty,
"无权访问"));
}
await next(context);
}
}