.Net Core 全局配置读取管理方法 ConfigurationManager

最近在学习.Net Core的过程中,发现.Net Framework中常用的ConfigurationManager在Core中竟然被干掉了。

  也能理解。Core中使用的配置文件全是Json,不像Framework使用的XML,暂时不支持也是能理解的,但是毕竟全局配置文件这种东西还挺重要的,阅读了一些文章后目前有3个解决方案。

一、引入扩展System.Configuration.ConfigurationManager


  这个扩展库可以直接在Nuget中获取。

  使用方法和说明见 .NET Core 2.0迁移技巧之web.config配置文件

  读取的文件类型和方法都跟.Net Framework中一致,而且仅需引入包就可以,瞬间很兴奋有木有!

  但是!在使用过过程中发现这个扩展有问题。项目运行过程中需修改我的app.config文件,对我项目中输出的内容没有丝毫影响,Debug发现获取到的值的确没有变化。重启项目都没有用。只有把项目重新编译才好使。

  不知道是不是因为我的打开方式不对,但是最终放弃这个方法。

二、引入扩展Microsoft.Extensions.Options.ConfigurationExtensions

  这个扩展库也可以直接在Nuget中获取。

  使用方法和说明见 ASP.NET Core实现类库项目读取配置文件

  这个可以读取application.json中的配置参数,不再使用XML可以说很好的贴近Core的设计理念。

  可惜,这个也有点美中不足的地方。首先跟上面的那个一样,运行时修改json文件读取到的内容不会改变,但是至少重启项目可以修改,这个让我欣慰很多。另外就是,这个方法采用的是反序列化的原理,也就是必须有一个跟配置文件对应的实体类才可以,这个感觉比较鸡肋,放弃。

三、自定义扩展方法

  这个是我这次说的重点,要是前面两个方法能满足读者你的需求,那么就没有必要看下去。

  废话少说,先上代码:

public class ConfigurationManager

    {

        /// <summary>

        /// 配置内容

        /// </summary>

        private static NameValueCollection _configurationCollection = new NameValueCollection();


        /// <summary>

        /// 配置监听响应链堆栈

        /// </summary>

        private static Stack<KeyValuePair<string, FileSystemWatcher>> FileListeners = new Stack<KeyValuePair<string, FileSystemWatcher>>();


        /// <summary>

        /// 默认路径

        /// </summary>

        private static string _defaultPath = Directory.GetCurrentDirectory() + "\\appsettings.json";


        /// <summary>

        /// 最终配置文件路径

        /// </summary>

        private static string _configPath = null;


        /// <summary>

        /// 配置节点关键字

        /// </summary>

        private static string _configSection = "AppSettings";


        /// <summary>

        /// 配置外连接的后缀

        /// </summary>

        private static string _configUrlPostfix = "Url";


        /// <summary>

        /// 最终修改时间戳

        /// </summary>

        private static long _timeStamp = 0L;


        /// <summary>

        /// 配置外链关键词,例如:AppSettings.Url

        /// </summary>

        private static string _configUrlSection { get { return _configSection + "." + _configUrlPostfix; } }



        static ConfigurationManager()

        {

            ConfigFinder(_defaultPath);

        }


        /// <summary>

        /// 确定配置文件路径

        /// </summary>

        private static void ConfigFinder(string Path)

        {

            _configPath = Path;

            JObject config_json = new JObject();

            while (config_json != null)

            {

                config_json = null;

                FileInfo config_info = new FileInfo(_configPath);

                if (!config_info.Exists) break;


                FileListeners.Push(CreateListener(config_info));

                config_json = LoadJsonFile(_configPath);

                if (config_json[_configUrlSection] != null)

                    _configPath = config_json[_configUrlSection].ToString();

                else break;

            }


            if (config_json == null || config_json[_configSection] == null) return;


            LoadConfiguration();

        }


        /// <summary>

        /// 读取配置文件内容

        /// </summary>

        private static void LoadConfiguration()

        {

            FileInfo config = new FileInfo(_configPath);

            var configColltion = new NameValueCollection();

            JObject config_object = LoadJsonFile(_configPath);

            if (config_object == null || !(config_object is JObject)) return;

           

            if (config_object[_configSection]!=null)

            {

                foreach (JProperty prop in config_object[_configSection])

                {

                    configColltion[prop.Name] = prop.Value.ToString();

                }

            }

            

            _configurationCollection = configColltion;

        }


        /// <summary>

        /// 解析Json文件

        /// </summary>

        /// <param name="FilePath">文件路径</param>

        /// <returns></returns>

        private static JObject LoadJsonFile(string FilePath)

        {

            JObject config_object = null;

            try

            {

                StreamReader sr = new StreamReader(FilePath, Encoding.Default);

                config_object = JObject.Parse(sr.ReadToEnd());

                sr.Close();

            }

            catch { }

            return config_object;

        }


        /// <summary>

        /// 添加监听树节点

        /// </summary>

        /// <param name="info"></param>

        /// <returns></returns>

        private static KeyValuePair<string, FileSystemWatcher> CreateListener(FileInfo info)

        {


            FileSystemWatcher watcher = new FileSystemWatcher();

            watcher.BeginInit();

            watcher.Path = info.DirectoryName;

            watcher.Filter = info.Name;

            watcher.IncludeSubdirectories = false;

            watcher.EnableRaisingEvents = true;

            watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Size;

            watcher.Changed += new FileSystemEventHandler(ConfigChangeListener);

            watcher.EndInit();


            return new KeyValuePair<string, FileSystemWatcher>(info.FullName, watcher);

          

        }


        private static void ConfigChangeListener(object sender, FileSystemEventArgs e)

        {

            long time = TimeStamp();

            lock (FileListeners)

            {

                if (time > _timeStamp)

                {

                    _timeStamp = time;

                    if (e.FullPath != _configPath || e.FullPath == _defaultPath)

                    {

                        while (FileListeners.Count > 0)

                        {

                            var listener = FileListeners.Pop();

                            listener.Value.Dispose();

                            if (listener.Key == e.FullPath) break;

                        }

                        ConfigFinder(e.FullPath);

                    }

                    else

                    {

                        LoadConfiguration();

                    }

                }

            }

        }


        private static long TimeStamp()

        {

            return (long)((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds * 100);

        }


        private static string c_configSection = null;

        public static string ConfigSection

        {

            get { return _configSection; }

            set { c_configSection = value; }

        }



        private static string c_configUrlPostfix = null;

        public static string ConfigUrlPostfix

        {

            get { return _configUrlPostfix; }

            set { c_configUrlPostfix = value; }

        }


        private static string c_defaultPath = null;

        public static string DefaultPath

        {

            get { return _defaultPath; }

            set { c_defaultPath = value; }

        }


        public static NameValueCollection AppSettings

        {

            get { return _configurationCollection; }

        }


        /// <summary>

        /// 手动刷新配置,修改配置后,请手动调用此方法,以便更新配置参数

        /// </summary>

        public static void RefreshConfiguration()

        {

            lock (FileListeners)

            {

                //修改配置

                if (c_configSection != null) { _configSection = c_configSection; c_configSection = null; }

                if (c_configUrlPostfix != null) { _configUrlPostfix = c_configUrlPostfix; c_configUrlPostfix = null; }

                if (c_defaultPath != null) { _defaultPath = c_defaultPath; c_defaultPath = null; }

                //释放掉全部监听响应链

                while (FileListeners.Count > 0)

                    FileListeners.Pop().Value.Dispose();

                ConfigFinder(_defaultPath);

            }

        }


    }

最开始设计的是采用缓存,每次调用比对文件的修改时间,大小等特征,出现变化从新载入配置。后来发现图样图森破!

  C#提供了专门监听文件系统的方法。所以从新设计了监听响应链堆栈来实现。

  

  使用说明:

    1、配置节点:

      可以直接写在项目默认的配置文件appsettings.json中 格式如下

{

  "AppSettings": {

    "Title": "Test",

    "Version": "1.2.1",

    "AccessToken": "123456@abc.com"

  }

}

 保证配置节点AppSettings存在,剩下的就是以Key-Value的形式来写属性,就可以。

    2、外部配置文件

      像.Net Framework中一样,可以通过外部配置文件来实现。格式如下

{

  "AppSettings.Url": "D:\\test\\app1.json"

}

采用格式是“配置节点名.外链后缀”的形式。可以设计多级外部配置文件,只要发现有外部配置节点就会向下寻找,并监听链上的所有节点文件的变化。

      但是需要注意的是:一旦存在外部配置节点,此文件中的配置节点和参数将不再参与解析

    3、可配置初始化参数

      包括默认文件路径在内的多个参数均可以修改,详情见代码。

      修改后需要手动调用RefreshConfiguration方法,以使配置内容生效,有点像事务处理。建议在项目的Startup方法中修改配置方法。

    4、使用

      跟.Net Framework中一样,直接调用ConfigurationManager.Appsettings["Title"]就可以了。


原文地址:http://www.cnblogs.com/kasimlz/p/7515810.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323632.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Http 持久连接与 HttpClient 连接池

转载自 Http 持久连接与 HttpClient 连接池 一、背景 HTTP协议是无状态的协议&#xff0c;即每一次请求都是互相独立的。因此它的最初实现是&#xff0c;每一个http请求都会打开一个tcp socket连接&#xff0c;当交互完毕后会关闭这个连接。 HTTP协议是全双工的协议&#x…

jdbc解析excel文件,批量插入数据至库中

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是&#xff1a;2022年5月20日09:32:38今天遇到了个这样的需求&#xff0c;解析excel表中的数据&#xff0c;以JDBC的方式&#xff0c;将数据批量更新至不同的数据表中。注意&…

线程2

public class test{/*** 测试延迟继承* param args*/public static void main(String[] args) {Cat catnew Cat();cat.start();//启动线程&#xff0c;会导致run函数的运行Dog dognew Dog();//创建一个线程对象Thread tnew Thread(dog);t.start();}} //继承Thread创建线程 clas…

.NET及.NET Core系统架构

.NET 官方架构指南 Microservices and Docker Containers Web Applications with ASP.NET 官网地址&#xff1a;https://www.microsoft.com/net/learn/architecture 三层及多层架构 Multitier Architecture ASP.NET N-Tier Architecture Schema Visual Studio N-Tier Examp…

Spring Boot 自动配置的 “魔法” 是如何实现的?

转载自 Spring Boot 自动配置的 “魔法” 是如何实现的&#xff1f; Spring Boot是Spring旗下众多的子项目之一&#xff0c;其理念是约定优于配置&#xff0c;它通过实现了自动配置&#xff08;大多数用户平时习惯设置的配置作为默认配置&#xff09;的功能来为用户快速构建出…

解决vue登录信息不及时更新问题

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年5月20日09:59:34 前面写过一篇文章&#xff0c;基于bladex框架实现的模拟登录&#xff0c;后来在测试的过程中发现了个问题&#xff0c;即A系统在跳转到本系…

学习ASP.NET Core,怎能不了解请求处理管道[2]: 服务器在管道中的“龙头”地位

ASP.NET Core管道由注册的服务器和一系列中间件构成。我们在上一篇中深入剖析了中间件&#xff0c;现在我们来了解一下服务器。服务器是ASP .NET Core管道的第一个节点&#xff0c;它负责完整请求的监听和接收&#xff0c;最终对请求的响应同样也由它完成。[本文已经同步到《AS…

for循环(二)

利用for循环按规律打出星星 #include<stdio.h>main(){int i,j;for(i0;i<10;i){for(j0;j<i;j){printf(" *"); }printf("\n");} }

接口方法上的注解无法被@Aspect声明的切面拦截的原因分析

转载自 接口方法上的注解无法被Aspect声明的切面拦截的原因分析 前言 在Spring中使用MyBatis的Mapper接口自动生成时&#xff0c;用一个自定义的注解标记在Mapper接口的方法中&#xff0c;再利用Aspect定义一个切面&#xff0c;拦截这个注解以记录日志或者执行时长。但是惊奇…

springboot实现用户统一认证、管理(单点登录)

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年5月25日13:44:16 最近和模拟登录杠上了&#xff0c;这不&#xff0c;又来了个需求&#xff0c;还是以这个技术点入手的。 需求大概是这样的&#xff1a;为了…

学习ASP.NET Core,怎能不了解请求处理管道[1]: 中间件究竟是个什么东西?

ASP.NET Core管道虽然在结构组成上显得非常简单&#xff0c;但是在具体实现上却涉及到太多的对象&#xff0c;所以我们在 “通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流程”&#xff08;上篇、中篇、下篇&#xff09; 中围绕着一个经过极度简化的模拟管道讲述…

springboot实现用户统一认证、管理

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是&#xff1a;2022年5月25日13:44:16最近和模拟登录杠上了&#xff0c;这不&#xff0c;又来了个需求&#xff0c;还是以这个技术点入手的。需求大概是这样的&#xff1a;为了统…

Mybatis 使用的 9 种设计模式,真是太有用了

转载自 Mybatis 使用的 9 种设计模式&#xff0c;真是太有用了 虽然我们都知道有26个设计模式&#xff0c;但是大多停留在概念层面&#xff0c;真实开发中很少遇到&#xff0c;Mybatis源码中使用了大量的设计模式&#xff0c;阅读源码并观察设计模式在其中的应用&#xff0c;…

springboot实现用户统一认证、管理-前端实现

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年6月2日15:43:51 上篇文章讲述了springboot中实现用户统一认证的具体内容&#xff0c;主要从后端角度出发的&#xff0c;其实大部分功能还是前端与后端交互的…

Unity3damp;amp;C#分布式游戏服务器ET框架介绍-组件式设计

前几天写了《开源分享 Unity3d客户端与C#分布式服务端游戏框架》&#xff0c;受到很多人关注&#xff0c;QQ群几天就加了80多个人。开源这个框架的主要目的也是分享自己设计ET的一些想法&#xff0c;所以我准备写一系列的文章&#xff0c;介绍下自己的思路跟设计&#xff0c;每…

springboot+vue实现用户统一认证、管理-前端实现

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是&#xff1a;2022年6月2日15:43:51上篇文章讲述了springboot中实现用户统一认证的具体内容&#xff0c;主要从后端角度出发的&#xff0c;其实大部分功能还是前端与后端交互的…

JS中 [] == ![]结果为true,而 {} == !{}却为false, 追根刨底

转载自 JS中 [] ![]结果为true&#xff0c;而 {} !{}却为false&#xff0c; 追根刨底 console.log( [] ![] ) // true console.log( {} !{} ) // false 在比较字符串、数值和布尔值的相等性时&#xff0c;问题还比较简单。但在涉及到对象的比较时&#xff0c;问题就变…

Centos7 amp;amp; Docker amp;amp; Jenkins amp;amp; ASP.NET Core

写在前面 Docker一直很火热&#xff0c;一直想把原本的Jenkins自动部署工具搬到Docker上面&#xff0c;无奈今年一直忙于各种事情&#xff0c;迟迟未实施这个事情&#xff0c;正好迎来了dotnet core 2.0 的正式发布&#xff0c;升级项目的同时&#xff0c;顺便直接将Jenkins搬到…

国民体质测定标准手册及标准解析成JSON文件计算分数,java解析excel文件

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年6月14日10:07:27 最近在做体质测评的功能&#xff0c;需要依据《国民体质测定标准手册及标准》&#xff0c;根据用户的个人信息&#xff0c;从而计算出各个…

getchar与putchar用法

#include<stdio.h>main(){int i;igetchar();//相当于char i;scanf("%c",&i); putchar(i);//相当于printf("%c",i); 需要i是字符才能输出不能是变量printf("\n");printf("%d",i);}输出结果一致 #include<stdio.h>main…