官方文档存在的问题
可能由于 Apollo 配置中心的客户端源码一直处于更新中, 导致其相关文档有些跟不上节奏, 部分文档写的不规范, 很容易给做对接的新手朋友造成误导.
比如, 我在参考如下两个文档使用传统 .NET 客户端做接入的时候就发现了些问题.
ctripcorp/apollo - .Net 客户端使用指南
ctripcorp/apollo.NET - .Net 客户端之与 System.Configuration.ConfigurationManager 集成
1. 两个文档关于标识应用身份的 AppId 的配置节点不一致.
2. 第二个文档关于应用配置发布环境的 Environment 配置节点的描述出现明显错误.
当然, 这些问题随时都有可能被修复. 若您看到文档内容与本文描述不符, 请以官方文档为准.
传统 .NET 项目快速接入
快速进入正题.
安装依赖包
在您项目的基础设施层, 通过 NuGet 包管理器或使用如下命令添加传统 .NET 项目使用的客户端:
Install-Package Com.Ctrip.Framework.Apollo.ConfigurationManager -Version 2.0.3
从上面的包名能看出什么? 我这里选装的是 2.0.3 的版本. 还有, 这应该是一个 Javaer 起的名字.
配置应用标识 & 服务地址
在您的启动项目中, 打开 App.config 或 web.config 配置文件, 在 < appSettings > 节点中增加如下节点:
- <!-- Change to the actual app id -->
- <add key="Apollo.AppID" value="R01001" />
- <add key="Apollo.MetaServer" value="http://localhost:8080" />
若您部署了多套 Config Service, 支持多环境, 请参考如下配置:
- <!-- Change to the actual app id -->
- <add key="Apollo.AppID" value="R01001" />
- <!-- Should change the apollo config service url for each environment
- -->
- <add key="Apollo.Env" value="DEV" />
- <add key="Apollo.DEV.Meta" value="http://localhost:8080" />
- <add key="Apollo.FAT.Meta" value="http://localhost:8081" />
- <add key="Apollo.UAT.Meta" value="http://localhost:8082" />
- <add key="Apollo.PRO.Meta" value="http://localhost:8083" />
配置完成后, 就可以准备在我们项目中使用 Apollo 客户端了.
二次封装代码
我们习惯在项目中使用第三方库的时候封装一层, 这种封装是浅层的, 一般都是在项目的基础设施层来做, 这样其他层使用就不需要再次引入依赖包.
不说了, 直接上代码吧.
代码结构大致如下:
├─MyCompany.MyProject.Infrastructure # 项目基础设施层
│ │
│ └─Configuration
│ ApolloConfiguration.cs # Apollo 分布式配置项读取实现
│ ConfigurationChangeEventArgs.cs # 配置更改回调事件参数
│ IConfiguration.cs # 配置抽象接口, 可基于此接口实现本地配置读取
- IConfiguration
- using System;
- using System.Configuration;
- namespace MyCompany.MyProject.Infrastructure
- {
- /// <summary>
- /// 配置抽象接口.
- /// </summary>
- public interface IConfiguration
- {
- /// <summary>
- /// 配置更改回调事件.
- /// </summary>
- event EventHandler<ConfigurationChangeEventArgs> ConfigChanged;
- /// <summary>
- /// 获取配置项.
- /// </summary>
- /// <param name="key"> 键 </param>
- /// <param name="namespaces"> 命名空间集合 </param>
- /// <returns></returns>
- string GetValue(string key, params string[] namespaces);
- /// <summary>
- /// 获取配置项.
- /// </summary>
- /// <typeparam name="TValue"> 值类型 </typeparam>
- /// <param name="key"> 键 </param>
- /// <param name="namespaces"> 命名空间集合 </param>
- /// <returns></returns>
- TValue GetValue<TValue>(string key, params string[] namespaces);
- /// <summary>
- /// 获取配置项, 如果值为 <see cref="null"/> 则取参数 <see cref="defaultValue"/> 值.
- /// </summary>
- /// <param name="key"> 键 </param>
- /// <param name="defaultValue"> 默认值 </param>
- /// <param name="namespaces"> 命名空间集合 </param>
- /// <returns></returns>
- string GetDefaultValue(string key, string defaultValue, params string[] namespaces);
- /// <summary>
- /// 获取配置项, 如果值为 <see cref="null"/> 则取参数 <see cref="defaultValue"/> 值.
- /// </summary>
- /// <typeparam name="TValue"> 值类型 </typeparam>
- /// <param name="key"> 键 </param>
- /// <param name="defaultValue"> 默认值 </param>
- /// <param name="namespaces"> 命名空间集合 </param>
- /// <returns></returns>
- TValue GetDefaultValue<TValue>(string key, TValue defaultValue, params string[] namespaces);
- }
- }
- ConfigurationChangeEventArgs
- using Com.Ctrip.Framework.Apollo.Model;
- using System.Collections.Generic;
- namespace MyCompany.MyProject.Infrastructure
- {
- public class ConfigurationChangeEventArgs
- {
- public IEnumerable<string> ChangedKeys => Changes.Keys;
- public bool IsChanged(string key) => Changes.ContainsKey(key);
- public string Namespace { get; }
- public IReadOnlyDictionary<string, ConfigChange> Changes { get; }
- public ConfigurationChangeEventArgs(string namespaceName, IReadOnlyDictionary<string, ConfigChange> changes)
- {
- Namespace = namespaceName;
- Changes = changes;
- }
- public ConfigChange GetChange(string key)
- {
- Changes.TryGetValue(key, out var change);
- return change;
- }
- }
- }
- ApolloConfiguration
- using System;
- using System.Configuration;
- using System.Globalization;
- using Com.Ctrip.Framework.Apollo;
- using Com.Ctrip.Framework.Apollo.Model;
- namespace MyCompany.MyProject.Infrastructure
- {
- public class ApolloConfiguration : IConfiguration
- {
- private readonly string _defaultValue = null;
- public event EventHandler<ConfigurationChangeEventArgs> ConfigChanged;
- private IConfig GetConfig(params string[] namespaces)
- {
- var config = namespaces == null || namespaces.Length == 0 ?
- ApolloConfigurationManager.GetAppConfig().GetAwaiter().GetResult() :
- ApolloConfigurationManager.GetConfig(namespaces).GetAwaiter().GetResult();
- config.ConfigChanged += (object sender, ConfigChangeEventArgs args) =>
- {
- ConfigChanged(sender, new ConfigurationChangeEventArgs(args.Namespace, args.Changes));
- };
- return config;
- }
- public string GetValue(string key, params string[] namespaces)
- {
- key = key ?? throw new ArgumentNullException(nameof(key));
- var config = GetConfig(namespaces);
- return config.GetProperty(key, _defaultValue);
- }
- public TValue GetValue<TValue>(string key, params string[] namespaces)
- {
- var value = GetValue(key, namespaces);
- return value == null ?
- default(TValue) :
- (TValue)Convert.ChangeType(value, typeof(TValue), CultureInfo.InvariantCulture);
- }
- public string GetDefaultValue(string key, string defaultValue, params string[] namespaces)
- {
- key = key ?? throw new ArgumentNullException(nameof(key));
- var config = GetConfig(namespaces);
- return config.GetProperty(key, defaultValue);
- }
- public TValue GetDefaultValue<TValue>(string key, TValue defaultValue, params string[] namespaces)
- {
- var value = GetDefaultValue(key, defaultValue, namespaces);
- return value == null ?
- default(TValue) :
- (TValue)Convert.ChangeType(value, typeof(TValue), CultureInfo.InvariantCulture);
- }
- }
- }
正确使用姿势
在使用之前需要先把 ApolloConfiguration 注册到应用容器中, 请参考如下代码:
- // 这里我们项目使用的 DI 框架是 `Autofac`, 按需修改吧, 记得将实例注册成单例模式.
- public class DependencyRegistrar : IDependencyRegistrar
- {
- public void Register(ContainerBuilder builder, ITypeFinder typeFinder)
- {
- builder.RegisterType<ApolloConfiguration>()
- .As<IConfiguration>()
- .Named<IConfiguration>("configuration")
- .SingleInstance();
- ...
- }
- public int Order
- {
- get { return 1; }
- }
- }
接下来就可以在项目中使用了, 请参考如下代码:
- public class UserController : BaseController
- {
- private readonly IConfiguration _configuration;
- public UserController(IConfiguration configuration)
- {
- _configuration = configuration;
- }
- public ActionResult Add(AddUserInput model)
- {
- if (ModelState.IsValid)
- {
- // 从 Apollo 分布式配置中心 项目 `R01001` 默认命名空间 `application` 下 读取配置项.
- model.Password = _configuration.GetValue("DefaultUserPassword");
- ...
- }
- ...
- }
- }
来源: https://www.cnblogs.com/esofar/p/11310921.html