本人主要利用IdentityServer4以及SignalR来实现,IdentityServer4作为认证,SignalR来交互配置,这里一些代码可能就是部分提出来,主要介绍实现原理及方法

实现配置中心核心的两个点我们要放在

1、配置文件如何传送

2、配置文件如何动态的更新

配置文件的传送结合SignalR来实现

思考:什么样的客户端可以来获取配置?

这里客户端我们配置了

这里我直接结合Identityserver4,配置客户端id,客户端密钥,配置中心地址、在配置一个IdentityServer4授权地址, 根据这些配置设计下配置中心的 数据库表,这里直接略

{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConfigCenter": {
"AuthUrl": "http://192.168.0.42:7000",
"ClientId": "configclient",
"ClientSecret": "configclient",
"ServerUrl": "http://localhost:6002"
}, "AllowedHosts": "*"
}

然后只有手鲁SignalR代码来出来连接消息交互了,不用在去早socket的轮子了,此处了略去,为了准备给自己的服务使用,只有把这个写成SDK

这里我们需要一个服务类:ClientServices 这个类用来出来 SignalR相关处理 以及配置Json数据的格式话,需要json配置转换成 .NetCore配置 ,开过配置中的 Data对象的都知道 这个Data中的格式是 {Logging:LogLevel,"1231"}这种键值对,怎么来把Json数据处理成为这个数据呢?后面介绍简便方法

这里对象类需要了解清楚 IConfigruationBuilder、IConfigurationProvider、IConfigurationSource ,这块不做介绍,而我们要做的就是结合这个来处理我们的配置

建立了三个项目来处理

ConfigCenter:配置服务端API接口,提供给UI 配置管理相关接口

ConfigCenterClient :客户端配置SDK,提供给服务端连接配置中心提供配置库

ConfigCenterTest::客户端服务测试API

配置文件动态更新

首先来开下ConfigurationProvider的源码

  //
// 摘要:
// Base helper class for implementing an Microsoft.Extensions.Configuration.IConfigurationProvider
public abstract class ConfigurationProvider : IConfigurationProvider
{
//
// 摘要:
// Initializes a new Microsoft.Extensions.Configuration.IConfigurationProvider
protected ConfigurationProvider(); //
// 摘要:
// The configuration key value pairs for this provider.
protected IDictionary<string, string> Data { get; set; } //
// 摘要:
// Returns the list of keys that this provider has.
//
// 参数:
// earlierKeys:
// The earlier keys that other providers contain.
//
// parentPath:
// The path for the parent IConfiguration.
//
// 返回结果:
// The list of keys for this provider.
public virtual IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
//
// 摘要:
// Returns a Microsoft.Extensions.Primitives.IChangeToken that can be used to listen
// when this provider is reloaded.
//
// 返回结果:
// The Microsoft.Extensions.Primitives.IChangeToken.
public IChangeToken GetReloadToken();
//
// 摘要:
// Loads (or reloads) the data for this provider.
public virtual void Load();
//
// 摘要:
// Sets a value for a given key.
//
// 参数:
// key:
// The configuration key to set.
//
// value:
// The value to set.
public virtual void Set(string key, string value);
//
// 摘要:
// Generates a string representing this provider name and relevant details.
//
// 返回结果:
// The configuration name.
public override string ToString();
//
// 摘要:
// Attempts to find a value with the given key, returns true if one is found, false
// otherwise.
//
// 参数:
// key:
// The key to lookup.
//
// value:
// The value found at key if one is found.
//
// 返回结果:
// True if key has a value, false otherwise.
public virtual bool TryGet(string key, out string value);
//
// 摘要:
// Triggers the reload change token and creates a new one.
protected void OnReload();

注意可以看到 Load方法都是虚方法,就是提供给我扩展的,接下来就是关键的一步在这个上面处理

构建自己的服务提供类来重写该方法,然后注入一个事件,提供给外部改变更新的能力

public class LYMConfigProvider : ConfigurationProvider
{
private ClientServices Client { get; } public LYMConfigProvider(ClientServices clientServices)
{
Client = clientServices;
} private void LoadData(IDictionary<string, string> values)
{
foreach (var item in values)
{

               if (item.Key.EndsWith("0"))
{
var likekey= item.Key.Substring(0, item.Key.Length - 1);
foreach (var da in Data)
{
if (da.Key.StartsWith(likekey))
{
Data.Remove(da.Key);
}
}
}
if (Data.ContainsKey(item.Key))
Data.Remove(item.Key);
Data.Add(item.Key, item.Value);
 } } public override void Load() { Client.Changed += (arg) => { LoadData(arg.customdata); base.OnReload(); }; var lst = Client.InitClientConfig(); LoadData(lst); } }

通过注册改变事件,外部就可以通过该事件来实现配置的更新了,值得注意的Load的时候我们需要初始化下配置,毕竟SignalR连接回复初始配置会出现延迟,导致Startup中IConfiguraion初始配置为空

接下来说一个关键的问题,就是得到的Json怎么序列化出来到Data中,而Data的类型又是:

//
// 摘要:
// The configuration key value pairs for this provider.
protected IDictionary<string, string> Data { get; set; }

不怕麻烦的朋友可以自己写递归各种转换,但是那样太麻烦了,只能用绝招了,通过ConfigurationBuilder对象Build出来的配置提供类都有一个Data,这个Data .NetCode已经帮我们出来好了,于是自己去构建了一个ConfigurationBuilder这样来处理看行不行?

  byte[] by = Encoding.UTF8.GetBytes(json);
MemoryStream ms = new MemoryStream(by);
var builder = new ConfigurationBuilder().AddJsonStream(ms).Build();

这里调试监控你可以看到Data是有值的,但是你就是取不到,会出现类型转换错误,就算得到Providers强转自己的类型还是会报错,且Data在ConfigurationProvider中是protect ,所以为了处理这个问题,我们不得不建立另外的自己的类来扩展下,构建自定义的配置资源以及配置提供类

因为这里是JsonStream,所以我们来扩展JsonStream就ok,这里我们提供了一个公共的GetData方法,来获取基类中的Data

 public class CustomJsonConfigrationProvider : JsonStreamConfigurationProvider
{
public CustomJsonConfigrationProvider(JsonStreamConfigurationSource jsonStreamConfigurationSource) : base(jsonStreamConfigurationSource)
{ }
public IDictionary<string, string> GetData()
{
return base.Data;
}
}
public class CustomJsonConfigrationSource: JsonStreamConfigurationSource
{
public override IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new CustomJsonConfigrationProvider(this);
}
}

所以如何把Json装换成.netcore中的配置,我们只需要如下代码即可:

    public IDictionary<string, string> BuildDictionary(string json)
{
byte[] by = Encoding.UTF8.GetBytes(json);
MemoryStream ms = new MemoryStream(by);
var source = new CustomJsonConfigrationSource();
source.Stream = ms;
var builder = new ConfigurationBuilder().Add(source).Build();
var data = builder.Providers.First() as CustomJsonConfigrationProvider;
return data.GetData();
}

接下来是校验成果的时候了,通过引用客户端SDK,并配置上自己的配置,准备下服务端的初始配置

 public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
} public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigLYMConfiguration() //这里就是我们SDK自己写的配置扩展方法
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}); }

这里服务端准备一段配置:{"data":"this the init configuration data"} 以及测试发送配置接口

下面我们通过服务的配置来修改下在刷新页面:

在环境配置中添加2两个配置

接下来我们用测试客户端启动起来看下,可以看到客户端实例的信息,以及使用的默认配置

并且访问下客户端站点

下面我们服务端启用Development配置然后刷新客户端看结果:

实现了针对通过一个客户端分布式部署统一更新配置,以及获取连接实例,针对指定服务实例更新配置的功能

参考文献:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#custom-configuration-provider

.NetCore下构建自己的服务配置中心-手动造轮子的更多相关文章

  1. 【微服务】之三:从零开始,轻松搞定SpringCloud微服务-配置中心

    在整个微服务体系中,除了注册中心具有非常重要的意义之外,还有一个注册中心.注册中心作为管理在整个项目群的配置文件及动态参数的重要载体服务.Spring Cloud体系的子项目中,Spring Clou ...

  2. SpringCloud04 服务配置中心、消息总线、远程配置动态刷新

    1 环境说明 JDK:1.8 MAVENT:3.5 SpringBoot:2.0.5.RELEASE SpringCloud:Finchley.SR1 2 创建服务注册中心(Eureka服务端) 说明 ...

  3. Spring Cloud Alibaba 整合 Nacos 实现服务配置中心

    在之前的文章 <Nacos 本地单机版部署步骤和使用> 中,大家应该了解了 Nacos 是什么?其中 Nacos 提供了动态配置服务功能 一.Nacos 动态配置服务是什么? 官方是这么说 ...

  4. MongoDB4.0在windows10下的安装与服务配置

    本地安装及网页测试 在官网下载最新的安装文件 下载地址 : https://www.mongodb.com/download-center#community 可以在MongoDB官网选择Commun ...

  5. .NetCore下构建自己的文件服务管理(UosoOSS)

    Web开发系统文件默认存储在wwwroot目录下面,现在越来越多的系统服务化了,UI也更加多元化,当然文件可以用第三方的文件服务,但是这里准备文件分离出来构建自己的文件服务配合数据库表来实现(Uoso ...

  6. SpringCloud服务配置中心

    SpringCloud Config简介 Spring Cloud Config 是 Spring Cloud 团队创建的一个全新项目,用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持 ...

  7. 微服务配置中心实战:Spring + MyBatis + Druid + Nacos

    在结合场景谈服务发现和配置中我们讲述了 Nacos 配置中心的三个典型的应用场景,包括如何在 Spring Boot 中使用 Nacos 配置中心将数据库连接信息管控起来,而在“原生”的 Spring ...

  8. Spring Cloud Alibaba系列(二)nacos作为服务配置中心

    Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持.使用 Spring Cloud Alibaba Nacos Config,您可 ...

  9. SpringCloud+Nacos实现服务配置中心(Hoxton版本)

    关于 Nacos Spring Cloud 的详细文档请参看:Nacos Config和Nacos Discovery. 通过 Nacos Server 和 spring-cloud-starter- ...

随机推荐

  1. mysql死锁com.mysql.cj.jdbc.exception.MYSQLTransactionRollbackException Deadlock found when trying to get lock;try restarting transaction

    1.生产环境出现以下报错 该错误发生在update操作中,该表并未建立索引,也就是只有InnoDB默认的主键索引,发生错误的程序是for循环中update. 什么情况下会出现Deadlock foun ...

  2. Linux:spool命令

    格式调整有以下参数: set echo on/off--是否显示脚本中的需要执行的命令 set feedback on/off--是否显示 select 结果之后返回多少行的提示 set linesi ...

  3. 莫烦python教程学习笔记——validation_curve用于调参

    # View more python learning tutorial on my Youtube and Youku channel!!! # Youtube video tutorial: ht ...

  4. 【简】题解 P4297 [NOI2006]网络收费

    传送门:P4297 [NOI2006]网络收费 题目大意: 给定一棵满二叉树,每个叶节点有一个状态(0,1),任选两个叶节点,如果这两个叶节点状态相同但他们的LCA所管辖的子树中的与他们状态相同的叶节 ...

  5. 02 - Vue3 UI Framework - 顶部边栏

    顶部边栏比较简单,而且首页和文档页都需要,所以我们先从顶部边栏做起 前文回顾点击 这里 返回阅读列表点击 这里 初始化 首先,在 components 文件夹下,创建一个 vue 组件,命名为 Top ...

  6. Redis5.0.8 Cluster集群部署

    目录 一.Redis Cluster简介 二.部署 三.创建主库 一.Redis Cluster简介 Redis Cluster集群是一种去中心化的高可用服务,其内置的sentinel功能可以提供高可 ...

  7. Jenkins获取jar包的快照号

    目录 一.简介 二.脚本 一.简介 主要用于打jar包的工程,显示快照包的名字.当jar打包完成后,会在target目录中,截取快照名. 二.脚本 1.脚本return-version.sh #!/b ...

  8. shell脚本 双向登陆免密

    一.简介 源码地址 日期:2018/4/23 介绍:用于hadoop的双向免密脚本,让填写机器互相之间免密登陆 效果图: 暂无 二.使用 适用:centos6+ 语言:中文 注意:执行前需要填写脚本里 ...

  9. 使用ANTLR解析CSV和JSON

    再续 ANTLR专题 ,有了前面的基础,下面开始用ANTLR写一些有趣且实用的程序. CSV和JSON这两种数据格式对软件开发人员来说最熟悉不过了,一般读写CSV或JSON格式的数据都会借助现成的.比 ...

  10. 微软要放弃Electron了???聊聊WebView2

    有好几个公众号发文说"微软要放弃Electron了",实际情况是微软旗下的Teams产品打算把Electron框架换成WebView2而已.接下来我就聊一下这个事情: 微软不会放弃 ...