文章目录
1.选项框架-服务组件集成配置的最佳实践
处理服务和配置的关系
1.1 特性
- 支持单例模式读取配置
- 支持快照
- 支持配置变更通知
- 支持运行时动态修改选项值
1.2 设计原则
- 接口分离原则(ISP),我们的类不应该依赖它不使用的配置
- 关注点分离(SoC),不同组件、服务、类之间的配置不应相互依赖或耦合
1.3 建议
- 为我们的服务设计xxxOptions
- 使用IOptions< xxxOptions>,IOptionsSnapshot< xxxOptions>,IOptionsMonitor< xxxOptions>作为服务的构造参数
VS 2022 Net 6.0
// 服务定义
namespace OptionsDemo.Services
{
public interface IOrderService
{
int ShowMaxOrderCount();
}
public class OrderService : IOrderService
{
OrderServiceOptions _options;
public OrderService(OrderServiceOptions options)
{
this._options = options;
}
public int ShowMaxOrderCount()
{
return _options.MaxOrderCount;
}
}
/// <summary>
/// 表示需要从配置中读取的值
/// </summary>
public class OrderServiceOptions
{
public int MaxOrderCount { get; set; } = 100;
}
}
// 服务注册
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddSingleton<OrderServiceOptions>();
builder.Services.AddSingleton<IOrderService,OrderService>();
// Controller定义
[HttpGet]
public int Get([FromServices]IOrderService orderService )
{
Console.WriteLine($"orderService.ShowMaxOrderCount : {orderService.ShowMaxOrderCount}");
return 1;
}
输出结果:
orderService.ShowMaxOrderCount : 100
如果将值和配置相绑定,需要使用Options框架,修改后代码如下
namespace OptionsDemo.Services
{
public interface IOrderService
{
int ShowMaxOrderCount();
}
// 只关心配置的值,不关心值得来源
public class OrderService : IOrderService
{
IOptions<OrderServiceOptions> _options;
public OrderService(IOptions<OrderServiceOptions> options)
{
this._options = options;
}
public int ShowMaxOrderCount()
{
return _options.Value.MaxOrderCount;
}
}
/// <summary>
/// 表示需要从配置中读取的值
/// </summary>
public class OrderServiceOptions
{
public int MaxOrderCount { get; set; } = 100;
}
}
2.选项数据热更新-让服务感知配置的变化
2.1 关键类型
- IOptionsMonitor< outTOptions>
- IOptionsSnapshot< outToptions>
2.2 场景
- 范围作用域类型使用IOptionsSnapshot
- 单例服务使用IOptionsMonitor
2.3 通过代码更新选项
- IPostConfigureOptions< TOptions>
// 服务注册使用Scope模式
builder.Services.AddScope<IOrderService,OrderService>();
public class OrderService : IOrderService
{
// 只需将IOptions改为IOptionsSnapshot即可
IOptionsSnapshot<OrderServiceOptions> _options;
public OrderService(IOptionsSnapshot<OrderServiceOptions> options)
{
this._options = options;
}
public int ShowMaxOrderCount()
{
return _options.Value.MaxOrderCount;
}
}
服务注册为Scope,并且使用IOptionsSnashot读取配置,每次请求都会重新计算并读取配置;
如果服务注册为Singleton,并且使用IOptionsMonitor读取配置,也会在配置发生变化后读取到最新的值;
IOptionsMonitor还有OnChange监听方法,可以监听配置变化,配置变化时可以触发事件,方法会监听运行目录和代码目录,可以使得我们在单例模式下监听到配置的变化
// 动态配置配置项
services.PostConfigure< OrderServiceOptions>(options =>{
options.MaxOrderCount +=100;
});
3.为选项数据添加验证:避免错误配置的应用接受用户流量
3.1 三种验证方法
- 直接注册验证函数
- 实现IValidateOptions< TOptions>
- 使用Microsoft.Extensions.Options.DataAnnottations
// 1.0
services.AddOptions< OrderServiceOptions>().Configure(options => {
configuration.Bind(options);
}).Validate(options => {
return options.MaxOrderCount < =100;
},"MaxOrderCount 不能大于100");
// 2.0 属性数注入
services.AddOptions< OrderServiceOptions>().Configure(options => {
configuration.Bind(options);
}).ValidateDataAnnotations();
// 修稿Options,定义验证属性
public class OrderServiceOptions
{
[Range(1,20)]
public int MaxOrderCount {get;set;} = 100;
}
// 3.0
public class OrderServiceValidateOptions : IValidateOptions< OrderServiceOptions>
{
public ValidateOptionsResult Validate()
{
if(options.MaxOrderCount > 100)
{
return ValidateOptionsResult.Fail("MaxService不能大于100");
}else{
return ValidateOptionsResult.Sucess;
}
}
}