.NET6之MiniAPI(五):选项

发布一下 0 0

选项是配置一个升级版,一般情况下是把一个范围内的配置包装成类型,以供使用,比如下面的RedisSetting,是Redis的配置参数:

{  "Logging": {    "LogLevel": {      "Default": "Information",      "Microsoft.AspNetCore": "Warning"    }  },  "AllowedHosts": "*",   "RedisSetting": {    "Host": "127.0.0.1",    "Port": 6379,    "Password": "123",    "ConnectionTimeOut": "10ms"  }}

可以采用下面的形式把配置类型 实体注入到容器(因为没有说注入这个知识点,这里可以理解为初始化)中。

var builder = WebApplication.CreateBuilder();builder.Services.Configure<RedisSetting>(builder.Configuration.GetSection("RedisSetting"));var app = builder.Build();

选项分为三种:普通选项目IOptions,热更新选项IOptionsSnapshot,监控选项IOptionsMonitor,下面分别说明。

IOptions选项

app.MapGet("/appinfo", (IOptions<RedisSetting> options) =>{    return options.Value;});

Demo结果

.NET6之MiniAPI(五):选项


热加载选项:IOptionsSnapshot

app.MapGet("/snapshot", (IOptionsSnapshot<RedisSetting> options) =>{    return options.Value;});

结果

.NET6之MiniAPI(五):选项

更新配置ConnectionTimeOut为15ms,在不重启服务的情况下,再次请求,结果会变成15ms

.NET6之MiniAPI(五):选项


监控选项:IOptionsMonitor

app.MapGet("/monitorstart", (IOptionsMonitor<RedisSetting> options) =>{    options.OnChange(redisSetting =>   {       app.Logger.LogInformation(options.CurrentValue.ToString());        });    return "Ok";});

调用监控

.NET6之MiniAPI(五):选项

当把ConnectionTimeOut更新成20ms时,OnChange会被触发,日志会打印出来

.NET6之MiniAPI(五):选项


利用监控特性可以与报警联合起来,当监控到配置有变化时,通知服务相关人知晓,是人为设置,还是被篡改,以便采取措施。

选项命名:

当相同的配置有两组时,选项命名就非常有用了,比如一主一备

  "RedisSettings": {    "Main": {      "Host": "127.0.0.1",      "Port": 6379,      "Password": "123",      "ConnectionTimeOut": "10ms"    },    "Prepare": {      "Host": "127.0.0.1",      "Port": 6380,      "Password": "456",      "ConnectionTimeOut": "12ms"    }  }

实体类可以用静态常量区分开来

public record RedisSetting{    public const string Main = "Main";    public const string Prepare = "Prepare";    public string? Host { get; set; }    public int Port { get; set; }    public string? Password { get; set; }    public string? ConnectionTimeOut { get; set; }}

分别注入配置即可

builder.Services.Configure<RedisSetting>(RedisSetting.Main,                                   builder.Configuration.GetSection("RedisSettings:Main"));builder.Services.Configure<RedisSetting>(RedisSetting.Prepare,                                    builder.Configuration.GetSection("RedisSettings:Prepare"));

不过只有IOptionsSnapshot和IOptionsMonitor能通过Get方法来获取命名的配置,IOptions没有实现Get方法

app.MapGet("/snapshotredissetting", (IOptionsSnapshot<RedisSetting> options) =>{    return options.Get(RedisSetting.Main);});app.MapGet("/monitorstart", (IOptionsMonitor<RedisSetting> options) =>{    options.OnChange(redisSetting =>   {       app.Logger.LogInformation(options.Get(RedisSetting.Main).ToString());       app.Logger.LogInformation(options.Get(RedisSetting.Prepare).ToString());   });    return options.CurrentValue;});

另外,为了提高配置数据的安全性,可以给配置选项增加验证,可以通过在配置实体类上增加DataAnnotations来验证,也可以自定义验证

public record RedisSetting{    public string? Host { get; set; }    public int Port { get; set; }    public string? Password { get; set; }    [RegularExpression(@"^\d+ms$", ErrorMessage = "格式不正确,必须是ms")]    public string? ConnectionTimeOut { get; set; }}

上面的ConnectionTimeOut是DataAnnotations方式,下面是自定义验证模式。

builder.Services.AddOptions<RedisSetting>()          .Bind(builder.Configuration.GetSection("RedisSetting"))          .ValidateDataAnnotations()          .Validate(config =>          {              if (config.Port < 1000)              {                  return false;              }              return true;          }, "端口不能少于1000");

如果验证更复杂,可以用自定义类实现,代码如下:

public class RedisSettingValidation : IValidateOptions<RedisSetting>{    public RedisSetting _config { get; init; }    public RedisSettingValidation(IConfiguration config)    {        _config = config.GetSection("RedisSetting")            .Get<RedisSetting>();    }    public ValidateOptionsResult Validate(string name, RedisSetting options)    {        string? vor=null;        var rx = new Regex(@"^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$");        if (options != null&&options.Host!=null)        {            var match = rx.Match(options.Host);            if (string.IsNullOrEmpty(match.Value))            {                vor = $"{options.Host} 格式不正确";            }            if (vor != null)            {                return ValidateOptionsResult.Fail(vor);            }        }        return ValidateOptionsResult.Success;    }}

添加验证类型

builder.Services.Configure<RedisSetting>(builder.Configuration.GetSection("RedisSetting"));builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions                            <RedisSetting>, RedisSettingValidation>());

版权声明:内容来源于互联网和用户投稿 如有侵权请联系删除

本文地址:http://0561fc.cn/69953.html