首页 > 其他分享 >Biwen.Settings添加对IConfiguration&IOptions的集成支持

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

时间:2024-05-21 15:18:44浏览次数:20  
标签:Settings Biwen IConfiguration public var IOptions

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;//直接对象注入

尽管这样已经足够好用且便捷,但是对于习惯了使用IConfigurationIOptions的朋友来说还是有些不习惯,其实实现对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

标签:Settings,Biwen,IConfiguration,public,var,IOptions
From: https://www.cnblogs.com/vipwan/p/18204135

相关文章

  • Zemax Optics Studio启动软件弹出Ansys Licensing Settings Utility
    博主在安装ZemaxOpticsStudio的过程中遇到了一个问题:安装完成后弹出AnsysLicensingSettingsUtility.解决方法:1.打开任务管理器,点击服务,确保“ANSYS,Inc.LicenseManagerCVD”服务和“ANSYSLicensingTomcat”服务状态是“正在运行”2.确保AnsysLicenseManagerRele......
  • C# app.config配置appSettings标签
    AppSettings标签主要用于应用程中的一些配置信息。比如上传文件的路径,需要用到的可能会根据不同环境改变的一些常量等。可以在配置文件添加可执行文件要的配置。usingSystem;usingSystem.Collections.Generic;usingSystem.Configuration;classProgram{staticvoid......
  • obsidian_plugins_settings
    settingsAdmonitionstitle:settingexample代码块类型:ad-{type}type对应表|Type|Aliases||---|---||note|note,seealso||abstract|abstract,summary,tldr||info|info,todo||tip|tip,hint,important||success|success,check,done||question|question,......
  • 中移铁通禹路由 ExportSettings 敏感信息泄露漏洞
    漏洞描述:该漏洞由于cgi-bin/ExportSettings.sh未对用户进行身份验证,导致攻击者能够未授权获取到路由器设置信息,包含了后台管理员用户的账号和密码fofa:title="互联世界物联未来-登录"鹰图:web.body="互联世界物联未来-登录"POC:GET/cgi-bin/ExportSettings.sh漏洞复现:......
  • Windows computer File share Settings
    1. Searchfor"Manageadvancedsharingsettings"intheWindowslowerleftcornerandclicktheresult.Asshownbelow①,② 2.Thenselectthetwoitemsinthepop-uppage,asshowninthefigure③ 3.Thensearchfor"TurnWindowsfeatu......
  • Windows Basics - Adjusting Your Settings
     AdjustingyoursettingsAtsomepoint,youmaywanttoadjustyourcomputer'ssettings.Forexample,youmightwanttochangeyourdesktopbackgroundormodifyyourInternetsettings.YoucanchangethesesettingsandmorefromtheControlPanel控制......
  • 在Biwen.QuickApi中整合一个极简的发布订阅(事件总线)
    闲来无聊在我的Biwen.QuickApi中实现一下极简的事件总线,其实代码还是蛮简单的,对于初学者可能有些帮助就贴出来,有什么不足的地方也欢迎板砖交流~首先定义一个事件约定的空接口publicinterfaceIEvent{}然后定义事件订阅者接口publicinterfaceIEventSubscriber<T>w......
  • Qt QSettings读写ini时 General 读不出来值
    简述我有一个配置文件,其中一个组General,怎么都读不出正确的值,全是空,但是别的组能读出来,改General2试试,果然可以,就怀疑是不是组名称被内置了。打开QSettings的帮助文档,搜索General,有内容,看下解释TheINIfileformathassevererestrictionsonthesyntaxofakey.Qt......
  • dotnet appsettings 配置文件读取
    Console.Config\Program.csusingMicrosoft.Extensions.Configuration;varbasePath=Directory.GetCurrentDirectory();varconfiguration=newConfigurationBuilder().SetBasePath(basePath)//设置基本路径.AddJsonFile("appsettings.json")//添......
  • PlayerSettings.WebGL.emscriptenArgs设置无效的问题
    1)PlayerSettings.WebGL.emscriptenArgs设置无效的问题2)java.lang.NoSuchMethodError的不明崩溃问题3)UE电影摄像机旋转问题4)Android设备游戏切后台后唤起,有概率变卡且黑屏这是第383篇UWA技术知识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助力大家更......