|
Biwen.Settings 是一个简易的配置项管理模块,主要的作用就是可以校验并持久化配置项,比如将自己的配置存储到数据库中,JSON文件中等
使用上也是很简单,只需要在服务中注入配置,
比如我们有一个GithubSetting的配置项,我们只需要定义好对象然后注入到Service中即可:- [Description("Github配置")]
- public class GithubSetting : ValidationSettingBase<GithubSetting>
- {
- [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);
- }
- }
复制代码- @inject GithubSetting GithubSetting;//直接对象注入
复制代码 尽管这样已经足够好用且便捷,但是对于习惯了使用IConfiguration和IOptions的朋友来说还是有些不习惯,其实实现对IConfiguration的支持还是很简单的,实现一下IConfigurationProvider即可,我们来动手实现一个名为BiwenSettingConfigurationProvider的Provider:- internal class Events
- {
- /// <summary>
- /// Channel队列
- /// </summary>
- public static readonly Channel<(bool IsChanged, string? SettingName)> ConfigrationChangedChannel = Channel.CreateUnbounded<(bool IsChanged, string? SettingName)>();
- }
- 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>
- /// <param name="cancellationToken"></param>
- /// <returns></returns>
- 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<string, string?> dics = [];
- using var scope = Settings.ServiceRegistration.ServiceProvider.CreateScope();
- var settingManager = scope.ServiceProvider.GetRequiredService<ISettingManager>();
- 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实现变更通知,- internal class ConfigurationMediratorDoneHandler(ILogger<ConfigurationMediratorDoneHandler> logger) : IMediratorDoneHandler
- {
- public Task OnPublishedAsync<T>(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:- public static class ServiceRegistration
- {
- internal static IServiceCollection AddBiwenSettingConfiguration(this IServiceCollection services)
- {
- //ConfigurationMediratorDoneHandler
- services.AddSingleton<IMediratorDoneHandler, ConfigurationMediratorDoneHandler>();
- return services;
- }
- /// <summary>
- /// 提供对IConfiguration,IOptions的支持
- /// </summary>
- /// <param name="manager"></param>
- /// <param name="autoRefresh"></param>
- /// <returns></returns>
- 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<ISettingManager>();
- var cache = sp.GetRequiredService<IMemoryCache>();
- //使用缓存避免重复反射
- 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扩展即可- builder.Configuration.AddBiwenSettingConfiguration(builder.Services, true);
复制代码 最后按下面的形式注册就可以了:- @inject GithubSetting GithubSetting;//直接对象注入
- @inject IOptions<GithubSetting> 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
来源:https://www.cnblogs.com/vipwan/p/18204135
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|