当前位置: 首页 > 工具软件 > ASP.NET Core > 使用案例 >

ASP .NET Core 配置框架

谷光誉
2023-12-01

在很久以前,还是单服务器的时候,而且服务器还部署在我们自己的服务器上,我对配置框架基本不怎么了解,因为配置都是定死的,基本上很难有变动,如今在公司开发的项目是微服务的,有很多的服务器,而且支持用户自己去写url,port这种配置,因此熟悉了一下.Net core的配置框架,看看怎么样可以灵活的部署项目。

读取配置的功能主要用.Net Core写好的实现就可以了。

using System.Collections.Generic;

namespace Microsoft.Extensions.Configuration
{
    
    public class ConfigurationBuilder : IConfigurationBuilder
    {
        public ConfigurationBuilder();

        public IDictionary<string, object> Properties { get; }

        public IList<IConfigurationSource> Sources { get; }

        public IConfigurationBuilder Add(IConfigurationSource source);

        public IConfigurationRoot Build();
    }
}

.Net Core 在Microsoft.Extensions.Configuration包下加了IConfigurationBuilder的很多拓展方法用来支持不同的配置方式。

内存配置模式

       public void MemoryCollectionConfiguration() 
        {
            var builder = new ConfigurationBuilder();
            builder.AddInMemoryCollection(new Dictionary<string, string>()
            {
                { "section1:key1","value1"},
                { "key2", "key2"},
                { "section1:key3","value3"},
            });
            var configurationRoot = builder.Build();
            var section1 = configurationRoot.GetSection("section1");
            var key1 = section1["key1"];
            var key2 = configurationRoot["key2"];
            var key3 = configurationRoot["section1:key3"];
            Console.WriteLine(key1); // value1
            Console.WriteLine(key2); // key2
            Console.WriteLine(key3); // value3
        }

命令行参数模式

launchSettings.json

"StartWeb": {
      "commandName": "Project",
      "commandLineArgs": "CommandLineKey1=value1 --CommandLineKey2=value2 CommandLineKey3=value3 -k1=k3",
      "launchBrowser": true,
      "launchUrl": "weatherforecast",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "Key1": "1"
      },
      "applicationUrl": "https://localhost:5001;http://localhost:5000"
}

 可以在lanuchSettings中添加命令行参数。

   public void CommandLineConfiguration(string[] args) 
        {
            var builder = new ConfigurationBuilder();
            var mapper = new Dictionary<string, string> { { "-k1", "CommandLineKey1" } };
            builder.AddCommandLine(args, mapper);
            var configurationRoot = builder.Build();
            var key1 = configurationRoot["CommandLineKey1"];
            var key2 = configurationRoot["CommandLineKey2"];
            var key3 = configurationRoot["CommandLineKey3"];
            Console.WriteLine(key1); // k3
            Console.WriteLine(key2); // value2
            Console.WriteLine(key3); // value3
        }

环境变量配置

在容器环境下,比如Docker或者K8S,因为容器之间具有隔离性,所以采用环境变量来配置的情况也是有很多的。

        public void EnviromentVariables() 
        {
            var builder = new ConfigurationBuilder();
            builder.AddEnvironmentVariables();
            var configurationRoot = builder.Build();
            var keyEnvironment = configurationRoot["ASPNETCORE_ENVIRONMENT"];
            var key1 = configurationRoot["Key1"];
            var java_home = configurationRoot["JAVA_HOME"];
            Console.WriteLine(keyEnvironment); // Development
            Console.WriteLine(key1); // 1
            Console.WriteLine(java_home); // D:\jdk\jdk8
        }

可以在lanuchSettings中添加环境变量。

 "StartWeb": {
      "commandName": "Project",
      "commandLineArgs": "CommandLineKey1=value1 --CommandLineKey2=value2 CommandLineKey3=value3 -k1=k3",
      "launchBrowser": true,
      "launchUrl": "weatherforecast",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "Key1": "1"
      },
      "applicationUrl": "https://localhost:5001;http://localhost:5000"
    }

文件配置

这个配置我用得最多,无论什么环境下都很好用,而且配置起来很直观,用的最多的文件类型应该就是json了,其他的如xml,ini,yml等都是相似的。

      public void FileConfiguration() 
        {
            var builder = new ConfigurationBuilder();
            builder.AddJsonFile("appsettings.Development.json", optional: false, reloadOnChange: false);
            var configurationRoot = builder.Build();
            var Default = configurationRoot["Logging:LogLevel:Default"];
            Console.WriteLine(Default); // Information
        }

json文件

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

监听配置源变化

如何监听数据源的变化还有有必要先了解一下接口。

通过前面的代码我们可以发现,不同种类的配置信息都是通过Add.....方法添加进builder的,那么就很有必要看一下IConfigurationBuilder接口的Add方法了。

public IConfigurationBuilder Add(IConfigurationSource source);

看一下参数和返回值

   
    public interface IConfigurationSource
    {
        IConfigurationProvider Build(IConfigurationBuilder builder);
    }

IConfigurationSource接口就非常的简单,返回一个Provider。

   
    public interface IConfigurationProvider
    {
     
        IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);

        IChangeToken GetReloadToken();

        void Load();
        
        void Set(string key, string value);
        
        bool TryGet(string key, out string value);
    }

发现了含有关键字的GetReloadToken,这个Token或许会用来唯一标识数据源,那么还缺一个OnReload方法来告诉框架数据源发生了改变。自己实现起来是有一点麻烦的,还好已经有一个写好的类了,我们直接使用Microsoft.Extensions.Configuration.ConfigurationProvider。

 
    public abstract class ConfigurationProvider : IConfigurationProvider
    {
        protected ConfigurationProvider();

        protected IDictionary<string, string> Data { get; set; }
       
        public virtual IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
    
        public IChangeToken GetReloadToken();
     
        public virtual void Load();
    
        public virtual void Set(string key, string value);
      
        public override string ToString();
       
        protected void OnReload();
    }

注意一个属性一个方法。

protected IDictionary<string, string> Data { get; set; }
protected void OnReload();

 很明显数据放在Data里,调用OnReload方法的时候就会触发自己注册的委托。

首先实现IConfigurationSource

   class MyConfigurationSource : IConfigurationSource
    {
        public IConfigurationProvider Build(IConfigurationBuilder builder) 
        {
            return new MyConfigurationProvider();
        }
    }

接下来实现一个会变化的数据源

 class MyConfigurationProvider : ConfigurationProvider, IConfigurationProvider
    {
        Timer timer;
        public MyConfigurationProvider() : base()
        {
            timer = new Timer();
            timer.Elapsed += Timer_Elapsed;
            timer.Interval = 3000;
            timer.Start();
        }
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            Load(true);
        }

        public override void Load() 
        {
            Load(false);
        }

        void Load(bool reload) 
        {
            this.Data["lastTime"] = DateTime.Now.ToString();
            if (reload) 
            {
                base.OnReload();
            }
        }
    }

使用

   public void HotConfiguration()
        {
            var builder = new ConfigurationBuilder();
            builder.Add(new MyConfigurationSource());
            var configRoot = builder.Build();
            var lastTime = configRoot["lastTime"];
            Console.WriteLine(lastTime);
            ChangeToken.OnChange(() => configRoot.GetReloadToken(), () =>
             {
                 Console.WriteLine(configRoot["lastTime"]);
             });

        }
2021/8/23 23:28:54
2021/8/23 23:28:57
2021/8/23 23:29:00
2021/8/23 23:29:03

每三秒变更一次。

当然我们可以更加像厂商提供的那样来进行注册,比如

builder.AddJsonFile("appsettings.Development.json")

 方法很简单,用个委托方法就行了。

namespace Microsoft.Extensions.Configuration
{
    public static class MyConfigurationBuilderExtensions
    {
        public static IConfigurationBuilder AddMyConfiguration(this IConfigurationBuilder builder) 
        {
            builder.Add(new MyConfigurationSource());
            return builder;
        }
    }
}

使用修改一下

   public void HotConfiguration()
        {
            var builder = new ConfigurationBuilder();
            builder.AddMyConfiguration();
            var configRoot = builder.Build();
            var lastTime = configRoot["lastTime"];
            Console.WriteLine(lastTime);
            ChangeToken.OnChange(() => configRoot.GetReloadToken(), () =>
             {
                 Console.WriteLine(configRoot["lastTime"]);
             });
        }

这样就很像了,厂商大概也都是这么实现的。

感谢您能读到这里,祝您生活幸福美满。

 类似资料: