ASP.NET Core 中读取JSON配置,自定义Redis配置提供程序示例

在ASP.NET中,一般情况下都是通过web.config来设置应用程序配置信息,要使用其它方式(比如JSON文件)来进行配置都需要自行扩展。而ASP.NET Core中就丰富的配置的方式,支持的配置方式包括:

  • Azure Key Vault
  • 命令行参数:dotnet run CommandLineKey1=value1 --CommandLineKey2=value2 /CommandLineKey3=value3
  • (已安装或已创建的)自定义提供程序
  • 目录文件
  • 环境变量
  • 内存中的 .NET 对象
  • 设置文件(INI,JSON,XML)

本文主要介绍JSON文件配置的使用方式。

默认情况下,使用 Startup.cs的CreateDefaultBuilder 初始化新的 WebHostBuilder 时,会自动加载appsettings.json和appsettings.{Environment}.json配置文件,如果你的配置想要放到其他JSON文件中,使用下面的方法加载配置文件:

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.SetBasePath(Directory.GetCurrentDirectory());
                config.AddJsonFile("config.json", optional: true, reloadOnChange: true);
            })
            .UseStartup<Startup>();
}

1. 读取JSON文件中的配置

假设 appsettings.json 内容如下:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Starship": {
    "name": "USS Enterprise",
    "registry": "NCC-1701",
    "class": "Constitution",
    "length": 304.8,
    "commissioned": false
  }
}

ASP.NET Core加载配置文件后会展平成如下形式:

Logging:LogLevel:DefaultWarning
AllowedHosts*
Starship:nameUSS Enterprise
Starship:registryNCC-1701
Starship:classConstitution
Starship:length304.8
Starship:commissionedfalse

要读取这些键值可以用几下几个方法:

  • GetValue:读取Key对应的值
    Configuration.GetValue<string>("Logging:LogLevel:Default")
  • GetSection:读取某个配置节点,返回 IConfigurationSection
    var configSection = _config.GetSection("Starship");
    configSection.GetValue<string>("name");
  • Exists:判断配置节点是否存在
    Configuration.GetSection("Starship").Exists();
  • GetChildren:获取子节点信息
    Configuration.GetSection("Starship").GetChildren();

要读取配置节点并绑定到类,使用下面的方法:

public class Starship
{
    public string Name { get; set; }
    public string Registry { get; set; }
    public string Class { get; set; }
    public decimal Length { get; set; }
    public bool Commissioned { get; set; }
}

var starship = Configuration.GetSection("Starship").Get<Starship>();

 

2. 自定义配置提供程序

ASP.NET Core中内置了丰富的配置提供程序,可以从内存数据、JSON文件、XML文件、命令行中加载配置。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.SetBasePath(Directory.GetCurrentDirectory());
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile(
                    "json_array.json", optional: false, reloadOnChange: false);
                config.AddJsonFile(
                    "starship.json", optional: false, reloadOnChange: false);
                config.AddXmlFile(
                    "tvshow.xml", optional: false, reloadOnChange: false);
                config.AddCommandLine(args);
            })
            .UseStartup<Startup>();

但如果要从Redis或数据库中读取配置怎么办呢?就需要进行扩展了,下面使用 Redis 配置提供程序作为示例:

2.1. 实现 IConfigurationSource 接口

public class RedisConfigurationSource : IConfigurationSource
    {
        public string RedisString { get; set; }
        public string ConfigKey { get; set; }
        public int ReloadTime { get; set; }

        public RedisConfigurationSource(string redisString, string configKey, int reloadTime)
        {
            RedisString = redisString;
            ConfigKey = configKey;
            ReloadTime = reloadTime;
        }

        public IConfigurationProvider Build(IConfigurationBuilder builder)
        {
            return new RedisConfigurationProvider(this);
        }
    }

2.2.继承 ConfigurationProvider 类,从 Redis 读取配置

public class RedisConfigurationProvider : ConfigurationProvider
    {
        private RedisConfigurationSource _source;
        private readonly Task _configurationListeningTask;

        public RedisConfigurationProvider(RedisConfigurationSource source)
        {
            _source = source;
            _configurationListeningTask = new Task(ListenToConfigurationChanges);
        }

        public override void Load()
        {
            LoadAsync().GetAwaiter();
        }

        public async Task LoadAsync()
        {
            Data = await QueryDataAsync();

            //启动配置更改监听
            if (_configurationListeningTask.Status == TaskStatus.Created)
                _configurationListeningTask.Start();
        }

        private async void ListenToConfigurationChanges()
        {
            if (_source.ReloadTime <= 0)
                return;

            while (true)
            {
                try
                {
                    await Task.Delay(TimeSpan.FromSeconds(_source.ReloadTime));
                    Data = await QueryDataAsync();
                    OnReload();
                }
                catch
                {
                }
            }
        }

        public async Task<IDictionary<string, string>> QueryDataAsync()
        {
            var rds = new CSRedis.CSRedisClient(_source.RedisString);
            RedisHelper.Initialization(rds);

            var tokens = JToken.Parse(await rds.GetAsync(_source.ConfigKey));

            return tokens
                    .Select(k => KeyValuePair.Create
                    (
                        k.Value<string>("Key"),
                        k.Value<string>("Value") != null ? JToken.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(k.Value<string>("Value")))) : null
                    ))
                    .Where(v => !string.IsNullOrWhiteSpace(v.Key))
                    .SelectMany(Flatten)
                    .ToDictionary(v => ConfigurationPath.Combine(v.Key.Split('/')), v => v.Value, StringComparer.OrdinalIgnoreCase);
        }

        #region 帮助方法
        //递归展平JSON节点
        private static IEnumerable<KeyValuePair<string, string>> Flatten(KeyValuePair<string, JToken> tuple)
        {
            if (!(tuple.Value is JObject value))
                yield break;

            foreach (var property in value)
            {
                var propertyKey = $"{tuple.Key}/{property.Key}";
                switch (property.Value.Type)
                {
                    case JTokenType.Object:
                        string v = Newtonsoft.Json.JsonConvert.SerializeObject(property.Value);
                        yield return KeyValuePair.Create(propertyKey, v);
                        break;
                    case JTokenType.Array:
                        break;
                    default:
                        yield return KeyValuePair.Create(propertyKey, property.Value.Value<string>());
                        break;
                }

            }
        }
        #endregion
    }

2.3.增加 Extensions

public static class RedisExtensions
    {
        public static IConfigurationBuilder AddRedisConfiguration(
            this IConfigurationBuilder builder, string redisString = "127.0.0.1:6379", 
            string configKey = "web1.config", int reloadTime = 15)
        {
            return builder.Add(new RedisConfigurationSource(redisString, configKey, reloadTime));
        }
    }

添加完上面的代码后,就能在 CreateWebHostBuilder()时使用自定义配置提供程序了。

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddRedisConfiguration("127.0.0.1:6379", "web1.json", 15);
                })
                .UseStartup<Startup>();

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值