Net6 控制台程序读取配置文件的几种方式

十年河东,十年河西,莫欺少年穷

学无止境,精益求精

本篇提供几种读取配置文件的方式,从简到难,步步加深

1、新建控制台程序

1.1、新增一个名称为application.json的配置文件

application.json

{
  "name": "杰克",
  "sex": "",
  "address": {
    "country": "美国",
    "city": "纽约",
    "port": "181"
  }
}

2、简单读取模式

2.1、项目引用 Microsoft.Extensions.Configuration 和 Microsoft.Extensions.Configuration.Json

        static void Main(string[] args)
        { 
            ConfigurationBuilder builder = new ConfigurationBuilder();
            builder.AddJsonFile("application.json", true, true);
            var ConfigRoot = builder.Build();//根节点
            //简单读取
            simple(ConfigRoot); 
        }

        static void simple(IConfigurationRoot ConfigRoot)
        {
            //Microsoft.Extensions.Configuration;
            //Microsoft.Extensions.Configuration.Json
            var name = ConfigRoot["name"];
            var country = ConfigRoot.GetSection("address:country").Value;
            var city = ConfigRoot.GetSection("address:city").Value;
            Console.WriteLine(name);
            Console.WriteLine(country);
            Console.WriteLine(city);
        }

3、选项模式读取

3.1、项目引用 Microsoft.Extensions.Configuration.Binder

        static void Main(string[] args)
        { 
            ConfigurationBuilder builder = new ConfigurationBuilder();
            builder.AddJsonFile("application.json", true, true);
            var ConfigRoot = builder.Build();//根节点
            //选项模式 
            bindCls(ConfigRoot);
        }

        static void bindCls(IConfigurationRoot ConfigRoot)
        {
            //Microsoft.Extensions.Configuration.Binder
            var adrs = ConfigRoot.GetSection("address").Get<addressDto>();
            Console.WriteLine("选项模式读取:"+adrs.country);
            Console.WriteLine("选项模式读取:" + adrs.city);
            Console.WriteLine("选项模式读取:" + adrs.port);
            //选项模式 读取根节点 
            var root = ConfigRoot.Get<rootDto>();
            Console.WriteLine("选项模式读取:" + root.name);
        }

选项模式读取是将json转化为实体类,因此我们还需要如下实体

    public class rootDto
    {
        public string name { get; set; }
        public string sex { get; set; }
        public addressDto address { get; set; }
    }

    public class addressDto
    {
        public string country { get; set; }
        public string city { get; set; }
        public int port { get; set; } //Json中为字符串,框架会做自动类型转换
    }

4、IOptions 模式读取【此方式支持依赖注入】

4.1、项目引用  Microsoft.Extensions.Options 

ASP.NET Core引入了Options模式,使用类来表示相关的设置组。简单的来说,就是用强类型的类来表达配置项,这带来了很多好处。
初学者会发现这个框架有3个主要的面向消费者的接口:IOptions<TOptions>、IOptionsMonitor<TOptions>以及IOptionsSnapshot<TOptions>。
这三个接口初看起来很类似,所以很容易引起困惑,什么场景下该用哪个接口呢?

关于三种接口应该用哪个的问题,请参考: https://www.cnblogs.com/wenhx/p/ioptions-ioptionsmonitor-and-ioptionssnapshot.html 

杨中科老师给的建议是使用IOptionsSnapshot

创建如下实体类及Options选项类

    public class rootDto
    {
        public string name { get; set; }
        public string sex { get; set; }
        public addressDto address { get; set; }
    }

    public class addressDto
    {
        public string country { get; set; }
        public string city { get; set; }
        public int port { get; set; } //Json中为字符串,框架会做自动类型转换
    }

    public class OptionsCls
    { 
        private readonly IOptionsSnapshot<rootDto> options;
        private readonly IOptionsSnapshot<addressDto> adsOptions;
        public OptionsCls(IOptionsSnapshot<rootDto> options, IOptionsSnapshot<addressDto> adsOptions)
        {
            this.options = options;
            this.adsOptions = adsOptions;
        }
        public void GetValue()
        {
            Console.WriteLine("========================================");
            Console.WriteLine(options.Value.name);
            Console.WriteLine(options.Value.sex);
        }
        public void GetAdsValue()
        {
            Console.WriteLine("========================================");
            Console.WriteLine(adsOptions.Value.country);
            Console.WriteLine(adsOptions.Value.city);
        }
    }
View Code

其中OptionsCls用来被注入到main函数

        static void Main(string[] args)
        { 
            ConfigurationBuilder builder = new ConfigurationBuilder();
            builder.AddJsonFile("application.json", true, true);
            var ConfigRoot = builder.Build();//根节点
             //Options 模式 
            optionsCls(ConfigRoot);
        }

        static void optionsCls(IConfigurationRoot ConfigRoot)
        {
            ServiceCollection services = new ServiceCollection();
            //Microsoft.Extensions.Options 
            services.AddOptions().Configure<rootDto>(A => ConfigRoot.Bind(A));
            services.AddOptions().Configure<addressDto>(A => ConfigRoot.GetSection("address").Bind(A));
            services.AddScoped<OptionsCls>();
            using (ServiceProvider provider = services.BuildServiceProvider())
            {
                var dto = provider.GetRequiredService<OptionsCls>();
                dto.GetAdsValue();
                dto.GetValue();
            }
        }

上述代码重点部分为:

 services.AddOptions().Configure<rootDto>(A => ConfigRoot.Bind(A));
 services.AddOptions().Configure<addressDto>(A => ConfigRoot.GetSection("address").Bind(A));

第一句代码可以理解为将整个配置文件映射为 rootDto类,第二句代码可以理解为将address接点下的json内容映射为 assressDto类

简单贴出Options模式运行如下:

 

 5、通过 JObject 自定义配置文件读取 【自己造轮子】

5.1、项目引入 Newtonsoft.Json 

为了测试自定义方法的有效性,我们将配置文件复杂化,如下

{
  "name": "杰克",
  "sex": "",
  "address": {
    "country": "美国",
    "city": "纽约",
    "port": "181",
    "cart": {
      "cat": "",
      "TomCat": {
        "sex": "",
        "name": "Tom",
        "frids": [1,2,3]
      }
    }
  }
}

自定义配置文件主方法:

    public class ConfigCommon
    {
        static ConfigCommon()
        {
#if DEBUG  //调试环境  读取 application.json
            File = "application.json";
            string str = System.IO.File.ReadAllText(Environment.CurrentDirectory + "\\" + File);
            objx = JsonConvert.DeserializeObject<JObject>(str);
#else       // 发布后环境 读取  appsettings.json
            File = "appsettings.json";
            string str = System.IO.File.ReadAllText(Environment.CurrentDirectory + "\\" + File);
            objx = JsonConvert.DeserializeObject<JObject>(str); 
#endif


        }
        public static string File { get; set; }

        public static JObject objx;

        public static object Get(params string[] Keys)
        { 
            var obj = objx;  
            JToken jobs = null;
            for (int i = 0; i < Keys.Length; i++)
            {
                string item = Keys[i];

                if (i == 0)
                {
                    jobs = obj[item];
                }
                else if (i != 0 && i != Keys.Length - 1)
                {
                    jobs = jobs[item];
                }
                else
                {
                    return jobs.Value<object>(item); 
                }
            }
            return null;
        } 
    }

根据配置文件,创建如下实体

    public class TomCatDto
    {
        public string sex { get; set; }
        public string name { get; set; }
        public object frids { get; set; }
    }

注意: frids 要定义为object 

Main 方法

        static void Main(string[] args)
        {
          var name = ConfigCommon.Get("address", "cart","TomCat", "name");
            if (name != null)
            { 
                Console.WriteLine(name.ToString());
            }
            var arys = ConfigCommon.Get("address", "cart", "TomCat", "frids");
            Console.WriteLine("============================");
            if (arys != null)
            {
              var lst = ((JArray)arys).ToObject<List<int>>();  ;
                foreach (var item in lst)
                {
                    Console.WriteLine("读取数组的值为:"+item);
                }
            }
            Console.WriteLine("============================");
            IEnumerable<JToken> TomModels = (IEnumerable<JToken>)ConfigCommon.Get("address", "cart", "TomCat");
            foreach(var item in TomModels)
            {
                Console.WriteLine(item.GetType());
                Console.WriteLine(item.ToString());
            }
            Console.Read();
        }

运行结果

 

 需要注意的是,上述自定义方法读取值为字符串的属性很简单,但是读取数组,对象等需要在调试中进行类型转化。

例如数组的读取

            var arys = ConfigCommon.Get("address", "cart", "TomCat", "frids");
            Console.WriteLine("============================");
            if (arys != null)
            {
              var lst = ((JArray)arys).ToObject<List<int>>();  ;
                foreach (var item in lst)
                {
                    Console.WriteLine("读取数组的值为:"+item);
                }
            }

调试过程中,得到的arys的真实类型为 JArray ,但方法的返回值为object ,因此我们需要根据调试的动态类型进行强制转换,然后再转为我们常用的数组类型

关于我扩展的这个自定义方法,对于读取字符串还是比较完美的,复杂类型需要调试过程中进行类型转化。

@天才卧龙的博客 

 

posted @ 2022-09-20 15:53  天才卧龙  阅读(4920)  评论(0)    收藏  举报