IT俱乐部 ASP.NET Biwen.Settings如何添加对IConfiguration&IOptions的集成支持

Biwen.Settings如何添加对IConfiguration&IOptions的集成支持

Biwen.Settings 是一个简易的配置项管理模块,主要的作用就是可以校验并持久化配置项,比如将自己的配置存储到数据库中,JSON文件中等
使用上也是很简单,只需要在服务中注入配置,
比如我们有一个GithubSetting的配置项,我们只需要定义好对象然后注入到Service中即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[Description("Github配置")]
public class GithubSetting : ValidationSettingBase
{
    [Description("Github用户名")]
    public string? UserName { get; set; } = "vipwan";
    [Description("Github仓库")]
    public string? Repository { get; set; } = "Biwen.Settings";
    [Description("Github Token")]
    public string? Token { get; set; } = "";
    public GithubSetting()
    {
        //验证规则
        RuleFor(x => x.UserName).NotEmpty().Length(3, 128);
        RuleFor(x => x.Repository).NotNull().NotEmpty().Length(3, 128);
        RuleFor(x => x.Token).NotNull().NotEmpty().Length(3, 128);
    }
}
1
@inject GithubSetting GithubSetting;//直接对象注入

尽管这样已经足够好用且便捷,但是对于习惯了使用IConfigurationIOptions的朋友来说还是有些不习惯,其实实现对IConfiguration的支持还是很简单的,实现一下IConfigurationProvider即可,我们来动手实现一个名为BiwenSettingConfigurationProvider的Provider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
internal class Events
{
    /// <summary>
    /// Channel队列
    /// </summary>
    public static readonly Channel ConfigrationChangedChannel = Channel.CreateUnbounded();
}
internal sealed class BiwenSettingConfigurationSource(bool autoRefresh = true) : IConfigurationSource
{
    public IConfigurationProvider Build(IConfigurationBuilder builder) => new BiwenSettingConfigurationProvider(autoRefresh);
}
internal class BiwenSettingConfigurationProvider : ConfigurationProvider, IDisposable, IAsyncDisposable
{
    public BiwenSettingConfigurationProvider(bool autoRefresh)
    {
        if (Settings.ServiceRegistration.ServiceProvider is null)
        {
            throw new BiwenException("必须首先注册Biwen.Setting模块,请调用:services.AddBiwenSettings()");
        }
        if (autoRefresh)
        {
            StartAlertAsync(cts.Token);
        }
    }
    private CancellationTokenSource cts = new();
    /// <summary>
    /// 使用Channel通知配置变更,如果有事件更新则重新加载
    /// </summary>
    ///
    ///
    public Task StartAlertAsync(CancellationToken cancellationToken)
    {
        _ = Task.Run(async () =>
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                _ = await Events.ConfigrationChangedChannel.Reader.ReadAsync(cancellationToken);
                Load();
                //通知配置变更
                OnReload();
            }
        }, cancellationToken);
        return Task.CompletedTask;
    }
    //从SettingManager中加载配置项
    public override void Load()
    {
        Dictionary dics = [];
        using var scope = Settings.ServiceRegistration.ServiceProvider.CreateScope();
        var settingManager = scope.ServiceProvider.GetRequiredService();
        var settings = settingManager.GetAllSettings()!;
        foreach (var setting in settings)
        {
            if (setting.SettingContent is null) continue;
            if (JsonNode.Parse(setting.SettingContent) is not JsonObject json) continue;
            foreach (var item in json)
            {
                dics.TryAdd($"{setting.SettingName}:{item.Key}", item.Value?.ToString());
            }
        }
        Data = dics;
    }
    public void Dispose()
    {
        cts.Cancel();
        Events.ConfigrationChangedChannel.Writer.Complete();
    }
    public ValueTask DisposeAsync()
    {
        cts.Cancel();
        Events.ConfigrationChangedChannel.Writer.Complete();
        return ValueTask.CompletedTask;
    }
}

内部通过Channel实现变更通知,

1
2
3
4
5
6
7
8
internal class ConfigurationMediratorDoneHandler(ILogger logger) : IMediratorDoneHandler
{
    public Task OnPublishedAsync(T @event) where T : ISetting, new()
    {            Events.ConfigrationChangedChannel.Writer.TryWrite((true, typeof(T).Name));
        logger.LogInformation($"Setting Changed: {typeof(T).Name},并通知Configuration刷新!");
        return Task.CompletedTask;
    }
}

然后老规矩我们扩展一下IServiceCollection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
   public static class ServiceRegistration
   {
       internal static IServiceCollection AddBiwenSettingConfiguration(this IServiceCollection services)
       {
           //ConfigurationMediratorDoneHandler
           services.AddSingleton();
           return services;
       }
       /// <summary>
       /// 提供对IConfiguration,IOptions的支持
       /// </summary>
       ///
       ///
       ///
       public static ConfigurationManager AddBiwenSettingConfiguration(
           this ConfigurationManager manager, IServiceCollection serviceDescriptors, bool autoRefresh = true)
       {
           var sp = Settings.ServiceRegistration.ServiceProvider ?? throw new BiwenException("必须首先注册Biwen.Setting模块,请调用:services.AddBiwenSettings()");
           //添加订阅
           if (autoRefresh)
           {
serviceDescriptors.AddBiwenSettingConfiguration();
           }
           IConfigurationBuilder configBuilder = manager;
           configBuilder.Add(new BiwenSettingConfigurationSource(autoRefresh));
           var settings = ASS.InAllRequiredAssemblies.ThatInherit(typeof(ISetting)).Where(x => x.IsClass && !x.IsAbstract).ToList();
           //注册ISetting
           settings.ForEach(x =>
           {
               //IOptions DI
               manager?.GetSection(x.Name).Bind(GetSetting(x, sp));
           });
           return manager;
       }
       static object GetSetting(Type x, IServiceProvider sp)
       {
           var settingManager = sp.GetRequiredService();
           var cache = sp.GetRequiredService();
           //使用缓存避免重复反射
           var md = cache.GetOrCreate($"GenericMethod_{x.FullName}", entry =>
           {
               MethodInfo methodLoad = settingManager.GetType().GetMethod(nameof(settingManager.Get))!;
               MethodInfo generic = methodLoad.MakeGenericMethod(x);
               return generic;
           });
           return md!.Invoke(settingManager, null)!;
       }
   }

最后在启动时调用AddBiwenSettingConfiguration扩展即可

1
builder.Configuration.AddBiwenSettingConfiguration(builder.Services, true);

最后按下面的形式注册就可以了:

1
2
3
4
@inject GithubSetting GithubSetting;//直接对象注入
@inject IOptions IOP; //通过IOptions注入
@inject IConfiguration Configuration;//IConfiguration
...

源代码我发布到了GitHub,欢迎star! 

https://github.com/vipwan/Biwen.Settings

https://github.com/vipwan/Biwen.Settings/tree/master/Biwen.Settings/Extensions/Configuration

到此这篇关于Biwen.Settings添加对IConfiguration&IOptions的集成支持的文章就介绍到这了,更多相关Biwen.Settings IConfiguration&IOptions集成内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!

本文收集自网络,不代表IT俱乐部立场,转载请注明出处。https://www.2it.club/code/asp-net/11726.html
上一篇
下一篇
联系我们

联系我们

在线咨询: QQ交谈

邮箱: 1120393934@qq.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部