.Net 4.X 提前用上 .Net Core 的配置模式以及热重载配置

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 1. 前言在提倡微服务及 Serverless 越来越普及的当下,传统 .Net 应用的配置模式往往依赖于一个名为 web.config 的 XML 文件,在可扩展性和可读性与时代脱节了。当然,我不会怂恿一下子把所有应用迁移到 .Net Core 上,本文将在尽量不引入 .Net Core 开发模式的前提下,获得最大的利益。

1. 前言

在提倡微服务及 Serverless 越来越普及的当下,传统 .Net 应用的配置模式往往依赖于一个名为 web.config 的 XML 文件,在可扩展性和可读性与时代脱节了。当然,我不会怂恿一下子把所有应用迁移到 .Net Core 上,本文将在尽量不引入 .Net Core 开发模式的前提下,获得最大的利益。

在开始之前,我们还是先说说 .Net Core 的配置模式有何优势以及最少的依赖。

1.1 .Net Core 配置模式的优势

  • 支持多种格式,如 Json、ini、Yaml、系统环境变量等
  • 不再依赖于 web.config ,可同时使用多种配置格式
  • 支持热重载配置,修改配置可以不用重启应用

1.2 最少依赖

nuget install  Microsoft.Extensions.Configuration
nuget install Microsoft.Extensions.Configuration.Binder
nuget install Castle.Windsor (其他 IOC 框架均可)

如果你安装的是最新的包,可能会遇到 Microsoft.Extensions.Configuration 系列 Nuget 包无法安装的问题,这主要取决当前应用的 .Net 版本,请参考下图,安装对应的版本(目前不支持 .Net 4.5 以下的应用)。
版本兼容情况

由于本人喜欢可读性高的 Json 文件,所以还安装 Microsoft.Extensions.Configuration.Json 的 Nuget 包。

2. 示例教程

本文在 Abp 2.1.3 的基础上实现 .Net Core 的配置模式以及热重载配置,更详细的过程可参照我在 Github 上的 提交历史

2.1 加载配置

.Net Core 配置模式的核心是一个名为 IConfigurationRoot 的接口对象,需要在应用入口中加载各种配置格式后创建一个 IConfigurationRoot 的实例,在传统的 .Net Web 应用中是在 Global.asax.cs 中赋值。

// ConfigurationExtenion.AppConfiguration 为一个静态的 IConfigurationRoot 实例。
 ConfigurationExtenion.AppConfiguration = new ConfigurationBuilder()
                .AddJsonFile("appsetting.json", optional: false, reloadOnChange: true)
                .AddJsonFile("appsetting01.json", optional: true, reloadOnChange: false)
                .Build();

简单地解释一下,我们需要(在根目录中) 有一个名为 "appsetting.json" 的 Json 文件,被修改的同时会重载 ConfigurationExtenion.AppConfiguration 。与之相反的 "appsetting01.json" 则允许不存在,即使存在,被修改时不会重载配置。

2.2 读取配置节点

加载配置后,我们需要把配置读取出来,在 IConfigurationRoot 中所有配置的信息都是存在于一个个节点中,我们可以根据节点名称来获取对应的类型对象。

        /// <summary>
        /// 获取节点配置
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="config"></param>
        /// <param name="sectionName"></param>
        /// <returns></returns>
        internal static TService GetSectionObject<TService>(IConfigurationRoot config, String sectionName)
        {
            var section = config.GetSection(sectionName);
            if (section == null)
            {
                throw new ArgumentException($" {sectionName} 未绑定,无法获取到配置节点信息!");
            }
            return section.Get<TService>();
        }

假设我们有一个这样的 "appsetting.json" 文件:

{
    "RedisConfiguration": {
      "InstanceDbId": 14,
      "InstanceRedisConnectionString": "127.0.0.1"
    },
    "MongoDbConfiguration": {
      "ConnectionString": "mongodb://127.0.0.1:27017/?connectTimeoutMS=300000",
      "DatatabaseName": "local"
    }
  }

如果我们要获取 MongoDbConfiguration 下的 ConnectionString 的值,那么我们可以这样获取:

var connectionString= GetSectionObject<String>(ConfigurationExtenion.AppConfiguration,"MongoDbConfiguration:ConnectionString");

2.3 设计配置类

在传统的 .Net 应用程序中,我们往往会使用一个静态变量去存放配置信息。而在有 IOC 的情况下,更好的方法是设计一个类来存放配置,如上面的 Json 文件我们可以设计如下两个类(在 Visual Studio 选择性黏贴 Json 会自动生成对象):

    public class RedisConfiguration
    {
        public int InstanceDbId { get; set; }
        public string InstanceRedisConnectionString { get; set; }
    }

    public class MongodbConfiguration
    {
        public string ConnectionString { get; set; }
        public string DatatabaseName { get; set; }
    }

2.4 注册配置

为了实现热重载配置,而不是一层不变的值,我们在 IOC 中获取配置类时,需要使用工厂方法获取。在 Windsor 中可以这么做:

        /// <summary>
        /// 注册方法
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="ioc"></param>
        /// <param name="factoryMethod"></param>
        private static void Register<TService>(IIocManager ioc, 
                                    Func<TService> factoryMethod) where TService : class
        {
            ioc.IocContainer
                .Register(
                    Component.For<TService>()
                        .UsingFactoryMethod(factoryMethod)
                        .LifestyleTransient() //这里的生命周期是瞬时的,单例不可以吗?
                );
        }

结合前面的获取配置节点,我们可以把两个静态方法组合起来创造一个新的静态方法,更方便我们使用。

        /// <summary>
        /// 注册配置
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="ioc"></param>
        /// <param name="config"></param>
        /// <param name="sectionName"></param>
        internal static void InitConfigService<TService>(IIocManager ioc, IConfigurationRoot config, String sectionName) where TService : class
        {
            Register(ioc, () =>
            {
                var service = GetSectionObject<TService>(config, sectionName);
                return service;
            });
        }

对于前面两个配置类,我们可以这样注入:

   ConfigurationExtenion.InitConfigService<RedisConfiguration>(IocManager,ConfigurationExtenion.AppConfiguration, "RedisConfiguration");
   ConfigurationExtenion.InitConfigService<MongodbConfiguration>(IocManager, ConfigurationExtenion.AppConfiguration, "MongoDbConfiguration");

2.5 获取配置

我在这里新增一个控制器方法获取 RedisConfiguration 对象,该方法使用属性注入获取指定的配置类,并返回给页面。

       public String GetRedisConfig()
        {
            var redisConfig = IocManager.Instance.Resolve<RedisConfiguration>();
            return redisConfig.ToJsonString();
        }

可以看到页面显示的与 Json 文件中结构一模一:
结果

2.6 热重载配置

与 .Net Core 不一样,在 .Net 4.X 的 Web 应用中只是稍微修改下 Json 文件都会让整个应用重启(修改 web.config 同样会重启),所以我将 "appsetting.json" 重命名为 "appsetting.conf" ,在运行时修改某些值,并重新访问控制器,可以看到对应的值变了。

效果

需要注意 IIS 的安全配置,Json 或者 ini 也许能直接通过 HTTP 获取!

3. 结语

通过简单的使用 .Net Core 配置模式,我们可以感受到其强大魅力,如果你对 .Net Core 更多的了解,以及感受两者的对比,可以对照我之前写过的一篇文章。对于热重载配置,.Net Core 中更多是使使用IOptionsSnapshot,而为了尽量少地引入 .Net Core 的特性,在这里只是简单地用了 IOC 的特性。当然,在不使用任何 IOC 的情况下(如果你害怕引入 IOC ),定义一个 IConfigurationRoot 的全局静态实例,也不失为一个折中的方案。



本文采用 知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议
转载请注明来源: 张蘅水
我在开发者头条中还会每日分享不错的技术文章,搜索 356194 即可查看
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
12天前
|
Java 物联网 C#
C#/.NET/.NET Core学习路线集合,学习不迷路!
C#/.NET/.NET Core学习路线集合,学习不迷路!
|
1月前
|
存储 开发框架 JSON
ASP.NET Core OData 9 正式发布
【10月更文挑战第8天】Microsoft 在 2024 年 8 月 30 日宣布推出 ASP.NET Core OData 9,此版本与 .NET 8 的 OData 库保持一致,改进了数据编码以符合 OData 规范,并放弃了对旧版 .NET Framework 的支持,仅支持 .NET 8 及更高版本。新版本引入了更快的 JSON 编写器 `System.Text.UTF8JsonWriter`,优化了内存使用和序列化速度。
|
16天前
|
Java 物联网 编译器
C#一分钟浅谈:.NET Core 与 .NET 5 区别
本文对比了 .NET Core 和 .NET 5,从历史背景、主要区别、常见问题及易错点等方面进行了详细分析。.NET Core 侧重跨平台支持和高性能,而 .NET 5 在此基础上统一了 .NET 生态系统,增加了更多新特性和优化。开发者可根据具体需求选择合适的版本。
39 7
|
12天前
|
人工智能 开发框架 前端开发
C#/.NET/.NET Core技术前沿周刊 | 第 12 期(2024年11.01-11.10)
C#/.NET/.NET Core技术前沿周刊 | 第 12 期(2024年11.01-11.10)
|
12天前
|
开发框架 网络协议 .NET
C#/.NET/.NET Core优秀项目和框架2024年10月简报
C#/.NET/.NET Core优秀项目和框架2024年10月简报
|
11天前
|
人工智能 开发框架 安全
C#/.NET/.NET Core技术前沿周刊 | 第 13 期(2024年11.11-11.17)
C#/.NET/.NET Core技术前沿周刊 | 第 13 期(2024年11.11-11.17)
|
1月前
|
人工智能 开发框架 C#
C#/.NET/.NET Core技术前沿周刊 | 第 6 期(2024年9.16-9.22)
C#/.NET/.NET Core技术前沿周刊 | 第 6 期(2024年9.16-9.22)
|
1月前
|
人工智能 开发框架 Cloud Native
C#/.NET/.NET Core技术前沿周刊 | 第 9 期(2024年10.07-10.13)
C#/.NET/.NET Core技术前沿周刊 | 第 9 期(2024年10.07-10.13)
|
1月前
|
开发框架 前端开发 API
C#/.NET/.NET Core优秀项目和框架2024年9月简报
C#/.NET/.NET Core优秀项目和框架2024年9月简报
|
1月前
|
开发框架 NoSQL MongoDB
C#/.NET/.NET Core开发实战教程集合
C#/.NET/.NET Core开发实战教程集合