欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-09-28 14:11:16
最近在学习.net core的过程中,发现.net framework中常用的configurationmanager在core中竟然被干掉了。 也能理解。core中使用...

最近在学习.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"]就可以了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。