.net5+nacos+ocelot 配置中心和服务发现实现

相关文章:手动造轮子——为Ocelot集成Nacos注册中心

出处:https://www.cnblogs.com/buruainiaaaa/p/14121176.html

作者:唐@ 

  最近一段时间 因公司业务需要,需要使用.net5做一套微服务的接口,使用nacos 做注册中心和配置中心,ocelot做网关。

因为ocelot 支持的是consol和eureka,如果使用nacos做服务发现,需要自己集成,以此记录下

  Nacos 支持基于 DNS 和基于 RPC 的服务发现(可以作为注册中心)、动态配置服务(可以做配置中心)、动态 DNS 服务。官网地址:https://nacos.io/en-us/

  ocelot 相信大家都比较熟悉,官网:https://ocelot.readthedocs.io/en/latest/index.html

 环境安装:

  nacos参考地址:https://blog.csdn.net/ooyhao/article/details/102744904

  基于.net版本的nacos  sdk:nacos-sdk-csharp-unofficial.AspNetCore  (此处有坑 :Nacos.AspNetCore 已经停止更新,代码已迁移,服务注册会有问题)

  SDK源码地址:https://github.com/nacos-group/nacos-sdk-csharp

配置中心:

  1.在nacos添加配置

 

    2.在.net 项目中 配置文件中 添加相关配置

 1  "nacos": {2     "ServerAddresses": [ "http://127.0.0.1:8849/" ],3     "DefaultTimeOut": 30000,4     "Namespace": "",5     "ListenInterval": 30000,6     "ServiceName": "ServiceName","RegisterEnabled": true,7     "Weight": 108   },9   "nacosData": {
10     "DataId": "nacosConfig",
11     "Group": "Pro"
12   }

3.在Startup.cs添加nacos  sdk的DI注册

1 services.AddNacos(Configuration);

 4.创建AppConfig类,定义构造函数:(从DI中获取INacosConfigClient对象)

 public AppConfig(IServiceCollection _services, IConfiguration _configuration){services = _services;configuration = _configuration;var serviceProvider = services.BuildServiceProvider();_configClient = serviceProvider.GetService<INacosConfigClient>();}

5.添加LoadConfig方法,加载配置中心的配置

代码说明:pKey入参 为配置文件中的key(nacosData),responseJson为配置中心的完整配置字符串,可以是json,可以是key=value模式,根据字符串格式,转为Dictionary中,放入静态私有对象中

/// <summary>/// 加载nacos配置中心/// </summary>/// <param name="pKey"></param>private async Task LoadConfig(string pKey){try{GetConfigRequest configRequest = configuration.GetSection(pKey).Get<GetConfigRequest>();if (configRequest == null || string.IsNullOrEmpty(configRequest.DataId)){return;}var responseJson = await _configClient.GetConfigAsync(configRequest);Console.WriteLine(responseJson);if (string.IsNullOrEmpty(responseJson)){return;}var dic = LoadDictionary(responseJson);if (pKey == commonNacosKey){commonConfig = dic;}else{dicConfig = dic;}}catch (Exception ex){throw ex;}}

6.添加监听:

ps:

AddListenerRequest对象为nacos sdk的监听请求对象,通过INacosConfigClient对象的AddListenerAsync方法,可以添加对nacos dataid=nacosConfig 的监听,监听的时间间隔设置可以为:ListenInterval
 1 /// <summary>2         /// 监控3         /// </summary>4         private void ListenerConfig()5         {6             AddListenerRequest request = configuration.GetSection("nacosData").Get<AddListenerRequest>();7             request.Callbacks = new List<Action<string>>() {8                 x=>{9                    var dic = LoadDictionary(x);
10                     foreach (var item in dicConfig.Keys)
11                     {
12                         if (dic.Keys.Any(p=>p==item))
13                         {
14                             if (dic[item] != dicConfig[item])
15                             {
16                                 dicConfig[item]=dic[item].Trim();
17                             }
18                         }else
19                         {
20                             dicConfig.Remove(item);
21                         }
22                     }
23                     foreach (var item in dic.Keys)
24                     {
25                         if (!dicConfig.Keys.Any(p=>p==item)){
26                             dicConfig.Add(item,dic[item]);
27                         }
28                     }
29                 }
30             };
31             var serviceProvider = services.BuildServiceProvider();
32             INacosConfigClient _configClient = serviceProvider.GetService<INacosConfigClient>();
33             _configClient.AddListenerAsync(request);
34         }

7.添加自动注入:

ps:如果需要在同一个项目中,获取多个配置,需要AppConfig对象的单列模式,这一点 自己注意下

 public static IServiceCollection AddLoadConfig(this IServiceCollection _services, IConfiguration _configuration){var config = new AppConfig(_services, _configuration);config.Load();return _services;}

 /******************************************************* 配置中心  end *************************************************************/

服务注册:

基于上面的配置信息 在自动注入中添加如下代码即可

services.AddNacosAspNetCore(conf);

启动之后 在nacos中,就可以看到此服务  如果在nacos 看到多个实列 或者 端口号和项目启动的端口号不一致,最好添加IP和port。

/***************************************************************服务注册  end***********************************************************************/

基于ocelot 的服务发现:

新建网关项目,添加ocelot和 nacos sdk 的nuget依赖

查看ocelot的官方文档就会发现,如果 能够取到nacos 中 服务的名称和服务里边可用实列的ip和port,然后把这些信息放入ocelot里边的, 就可以通过ocelot访问到这些服务接口

然后在通过自定义监听器,就可以实现想要的效果

通过上面的配置中心的配置方式,在nacos中 添加 ocelot 的模板配置

{"Routes": [{"DownstreamHostAndPorts": [{"Host": "localhost","Port": 5000}],"DownstreamPathTemplate": "/{url}","DownstreamScheme": "http","UpstreamHttpMethod": ["GET", "POST", "DELETE", "PUT"],"UpstreamPathTemplate": "/OrderServer/{url}","LoadBalancerOptions": {"Type": "RoundRobin"}}, {"DownstreamHostAndPorts": [{"Host": "localhost","Port": 5000}],"DownstreamPathTemplate": "/{url}","DownstreamScheme": "http","UpstreamHttpMethod": ["GET", "POST", "DELETE", "PUT"],"UpstreamPathTemplate": "/ProductServer/{url}"}],"ServiceDiscoveryProvider": {},"GlobalConfiguration": {}
}

关于ocelot的Startup.cs的相关配置  这里就不赘述了,网上有很多。

这里的关键是,从nacos中拉取服务列表,然后根据ocelot的配置模板,生成需要的ocelot的配置信息,然后放入ocelot中

获取nacos中所有的服务列表 

ps:通过INacosNamingClient对象的ListServicesAsync方法,获取nacos 的服务

/// <summary>/// 获取所有服务/// </summary>/// <param name="serviceProvider"></param>/// <param name="_servicesRequest"></param>/// <returns></returns>private async Task<List<ListInstancesResult>> GetServerListener(IServiceProvider serviceProvider, object _servicesRequest){ListServicesRequest request = (ListServicesRequest)_servicesRequest;try{var _namingClient = serviceProvider.GetService<INacosNamingClient>();var res = await _namingClient.ListServicesAsync(request);List<ListInstancesResult> resultList = new List<ListInstancesResult>();if (res.Count > 0){List<Task<ListInstancesResult >> taskList = new List<Task<ListInstancesResult>>();foreach (var item in res.Doms){var taskItem = GetListInstancesResult(_namingClient,item);taskList.Add(taskItem);}Task.WaitAll(taskList.ToArray());foreach (var item in taskList){resultList.Add(item.Result);}}return resultList;}catch (Exception ex){LoggerLocal.Error(ex.Message, ex);return new List<ListInstancesResult>();}}

 将nacos的服务和配置中心的ocelot模板转换为ocelot的配置对象

/// <summary>/// nacos中的服务 转为ocelot对象的路由/// </summary>/// <param name="fileConfiguration"></param>/// <param name="listInstancesResults"></param>/// <returns></returns>private FileConfiguration InstancesResultToFileConfiguration(FileConfigurationTemplate fileConfiguration, List<ListInstancesResult> listInstancesResults) {if (fileConfiguration.RouteTemplate == null || fileConfiguration.RouteTemplate.Count == 0){throw new Exception("路由不能为空");}var result = new FileConfiguration() {GlobalConfiguration = fileConfiguration.GlobalConfiguration,Aggregates = fileConfiguration.Aggregates,DynamicRoutes = fileConfiguration.DynamicRoutes,Routes = new List<FileRoute>()};nacosServerModelList.ServerInfo = new List<ServerInfo>();var routeList = fileConfiguration.RouteTemplate;var defaultRoute = fileConfiguration.RouteTemplate.Find(p=>p.RoutesTemplateName=="common");fileConfiguration.Routes = new List<FileRoute>();foreach (var item in listInstancesResults){var routeTemp = routeList.Find(p => p.ServiceName.ToLower() == item.Dom.ToLower());if (routeTemp == null){routeTemp = defaultRoute;}var newRouteTmp = CopyTo(routeTemp);newRouteTmp.UpstreamPathTemplate = "/" + item.Dom + "/{url}";newRouteTmp.DownstreamPathTemplate = "/{url}";newRouteTmp.DownstreamHostAndPorts = new List<FileHostAndPort>();if (item.Hosts.Count > 0){foreach (var host in item.Hosts){newRouteTmp.DownstreamHostAndPorts.Add(new FileHostAndPort(){Host = host.Ip,Port = host.Port,});}}if (newRouteTmp.DownstreamHostAndPorts.Count > 0){result.Routes.Add(newRouteTmp);nacosServerModelList.ServerInfo.Add(new ServerInfo() { Name = item.Dom });}}UpdSwaggerUrlAction(serviceProvider, nacosServerModelList);return result;}private  FileRoute CopyTo(RouteTemplate s){var result = new FileRoute() { AddClaimsToRequest=s.AddClaimsToRequest,DangerousAcceptAnyServerCertificateValidator=s.DangerousAcceptAnyServerCertificateValidator,DelegatingHandlers=s.DelegatingHandlers,DownstreamHeaderTransform=s.DownstreamHeaderTransform,DownstreamHostAndPorts=s.DownstreamHostAndPorts,DownstreamHttpMethod=s.DownstreamHttpMethod,DownstreamHttpVersion=s.DownstreamHttpVersion,DownstreamPathTemplate=s.DownstreamPathTemplate,SecurityOptions=s.SecurityOptions,DownstreamScheme=s.DownstreamScheme,ChangeDownstreamPathTemplate=s.ChangeDownstreamPathTemplate,AddHeadersToRequest=s.AddHeadersToRequest,AddQueriesToRequest=s.AddQueriesToRequest,AuthenticationOptions=s.AuthenticationOptions,FileCacheOptions=s.FileCacheOptions,HttpHandlerOptions=s.HttpHandlerOptions,Key=s.Key,LoadBalancerOptions=s.LoadBalancerOptions,Priority=s.Priority,QoSOptions=s.QoSOptions,RateLimitOptions=s.RateLimitOptions,RequestIdKey=s.RequestIdKey,RouteClaimsRequirement=s.RouteClaimsRequirement,RouteIsCaseSensitive=s.RouteIsCaseSensitive,ServiceName=s.ServiceName,ServiceNamespace=s.ServiceNamespace,Timeout=s.Timeout,UpstreamHeaderTransform=s.UpstreamHeaderTransform,UpstreamHost=s.UpstreamHost,UpstreamHttpMethod=s.UpstreamHttpMethod,UpstreamPathTemplate=s.UpstreamPathTemplate,};return result;}

 

将配置信息放入ocelot里边

ps:这个地方 需要看ocelot的源码,才知道这中间的对象转换逻辑

1  private void SetOcelotConfig(FileConfiguration configuration)
2         {
3             
4             var internalConfigCreator = serviceProvider.GetService<IInternalConfigurationCreator>();
5             Task<Response<IInternalConfiguration>> taskResponse = internalConfigCreator.Create(configuration);
6             taskResponse.Wait();
7             IInternalConfigurationRepository internalConfigurationRepository = serviceProvider.GetService<IInternalConfigurationRepository>();
8             internalConfigurationRepository.AddOrReplace(taskResponse.Result.Data);
9         }

自定义监听器:

ps:isLoadUri 防止处理过慢,监听服务 多次监听

routesMd5:判断监听到的服务 是否需要放入ocelot

自定义监听的方式与nacos sdk中,监听配置中心的方式类似,有兴趣可以看看sdk的源码

/// <summary>/// 获取nacos里边的所有服务信息,同时自定义服务监听/// </summary>/// <param name="serviceProvider"></param>/// <returns></returns>private async Task<List<ListInstancesResult>> GetServerList(IServiceProvider serviceProvider){var request = new ListServicesRequest{PageNo = 1,PageSize = 100,};List<ListInstancesResult> listInstancesResults = await GetServerListener(serviceProvider, request);//return listInstancesResults;var timeSeconds = 1000 * 10;Timer timer = new Timer(async x =>{//防止重复Timerif (isLoadUri){return;}isLoadUri = true;List<ListInstancesResult> listInstancesList = await GetServerListener(serviceProvider, x);GetConfigRequest configRequest = configuration.GetSection("nacosData").Get<GetConfigRequest>();INacosConfigClient _configClient = serviceProvider.GetService<INacosConfigClient>();Task<string> taskResult = _configClient.GetConfigAsync(configRequest);taskResult.Wait();var responseJson = taskResult.Result;if (listInstancesList.Count>0){var fileConfiguration = InstancesResultToFileConfiguration(JsonConvert.DeserializeObject<FileConfigurationTemplate>(responseJson), listInstancesList);responseJson = JsonConvert.SerializeObject(fileConfiguration);var rMd5 = HashUtil.GetMd5(responseJson);if (!rMd5.Equals(routesMd5)){SetOcelotConfig(fileConfiguration);routesMd5 = rMd5;}}isLoadUri = false;}, request, timeSeconds, timeSeconds);timers.Add(timer);return listInstancesResults;}

相关文章:手动造轮子——为Ocelot集成Nacos注册中心

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

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

相关文章

数据科学与python语言——Pandas统计分析基础(时间转换+聚合)

Pandas统计分析基础&#xff08;时间转换聚合&#xff09;实验要求一实验二要求全部代码实验要求一 #M表的时间戳类型转为datetime data_Mete[TIMESTAMP]pd.to_datetime(data_Mete[TIMESTAMP],format%Y%m%d%H%M%S)data_VI[Date]pd.to_datetime(data_VI[Date],format%Y/%m/%d) p…

用keil怎么擦除_分享STM32 FLASH 擦除(以及防止误擦除程序代码)、写入

编译环境&#xff1a;我用的是(Keil)MDK4.7.2stm32库版本&#xff1a;我用的是3.5.0一、本文不对FLASH的基础知识做详细的介绍&#xff0c;不懂得地方请查阅有关资料。对STM32 内部FLASH进行编程操作&#xff0c;需要遵循以下流程&#xff1a;FLASH解锁清除相关标志位擦除FLASH…

如何在 ASP.NET Core 中使用 Quartz.NET 执行任务调度

当我们在web开发中&#xff0c;常常会遇到这么一个需求&#xff0c;在后台执行某一项具体的任务&#xff0c;具体的说就是这些任务必须在后台定时执行。Quartz.NET 是一个开源的 JAVA 移植版&#xff0c;它有着悠久的历史并且提供了强大的 Cron 表达式&#xff0c;这篇我们就来…

数据科学与python——Pandas统计分析基础(数据堆叠+数据清洗)

Pandas统计分析基础数据堆叠数据清洗一.合并数据&#xff1a;获取完整的数据集。1.读取数据2.将两个csv文件按照mete.csv文件的日期对齐3.纵向合并数据data1与data24.使用drop_duplicates()函数去除重复值二.异常值处理&#xff1a;去除data3中GPP中的异常点1.根据3σ原则检测异…

python 为什么动态语言图片_聊聊动态语言那些事(Python)

动态编程语言是高级程序设计语言的一个类别&#xff0c;在计算机科学领域已被广泛应用。它是一类在运行时可以改变其结构的语言&#xff1a;例如新的函数、对象、甚至代码可以被引进&#xff0c;已有的函数可以被删除或是其他结构上的变化。动态语言目前非常具有活力&#xff0…

容器的那点事

当我们的后端服务器不够用的时候&#xff0c;我们可以通过容器技术&#xff0c;可以快速的把这些服务器全部虚拟出来&#xff0c; 当然这个虚拟跟虚拟机是不一样的&#xff0c;比虚拟机的方式快多了&#xff0c;早期阿里的淘宝平台如果整个坏掉了&#xff0c;重新搭建部署起来需…

lqb——修改数组

思路 **常规思路用哈希表的思想,设置bool数组标识是否被占用过,但是发生矛盾时将会造成查找需要遍历整个数组,比如,1,2,3……100000已连续占用,此时再插入1,将会一直遍历这100000个数,极端情况下,插入100000个1,将是n平方的复杂度。 如何快速查找到插入位置,这就引…

bp神经网络训练_数据分析模型6——神经网络基础(人工智能的底层模型)

未经许可请勿转载更多数据分析内容参看这里今天我们来学习人工智能的底层模型——神经网络&#xff08;NEURAL NETWORKS&#xff09;&#xff0c;现在比较热门的一个模型是深度学习&#xff0c;深度学习的基础也是神经网络&#xff0c;要学好深度学习&#xff0c;神经网络不了解…

四种最令人讨厌的编程语言:Java、Javascript、C++和Perl

喜欢就关注我们吧&#xff01;TIOBE 12 月榜单已于日前公布&#xff0c;在最新的排行榜中&#xff0c;C 语言仍高居榜首&#xff0c;其次分别是 Java、Python 和 C。在编程语言这一领域中&#xff0c;许多编程语言都会随着时间的推移而经历人气的激增&#xff0c;以及历史迭代之…

机器学习之数据预处理——特征编码(标签编码,独热编码)

机器学习之数据预处理——特征编码 数据预处理——特征编码离散数据的编码标签编码sklearn LabelEncoder(使用fit_transform函数)sklearn LabelEncoder(反向变换可以用函数 inverse_transform)独热编码sklearn OneHotEncoder机器学习里有一句名言:数据和特征决定了机器学习的上…

微软用的工具,统一财务三大表及高级分析通用模板

虽然罗叔并非财务专业&#xff0c;但大概了解一些财务常识。例如财务报表的三大报表以及一些常见分析等。本月《BI真经》视频课程即将就绪&#xff0c;后续罗叔将和大家开展更多的业务研究。我们知道&#xff0c;PowerBI 在绘制某些报告时候很难&#xff0c;初学者根本无法实现…

文件 单片机_如何查看你写的单片机程序有多大?

单片机我们都用过&#xff0c;我们知道单片机的FLASH有4K的&#xff0c;有8K的&#xff0c;单片机程序我们也写过&#xff0c;但是我们写好的程序有多大&#xff0c;你知道吗&#xff1f;程序写好并编译后生成hex文件&#xff0c;这个hex文件就是要下载到单片机里的文件&#x…

机器学习之数据预处理——数据清洗(缺失值、异常值和重复值的处理)

机器学习之数据预处理——数据清洗缺失值、异常值和重复值的处理 基础知识技术点总结数据列缺失的处理方法1、丢弃(缺失值处理)1、生成一份随机数据2、查看哪些值缺失3、获得含有NA的列4、获取全部为NA的列5、丢弃缺失值2、补全(缺失值处理)1、使用sklearn将缺失值替换为特…

小说中场景的功能_如何让你的小说中的场景转换自如?

很多人很头疼场景、时间转换要怎么办&#xff0c;可以用章节作为转换的过渡&#xff0c;那么章节内呢&#xff1f;我看到最普通的做法就是画分割线&#xff0c;殊不知这种做法在稍微有点阅读功底的读者眼中都是很……怎么说&#xff0c;很没品吗&#xff1f;嗯&#xff0c;或许…

夏虫不可语冰

此次事件让我再次体会到了什么是“夏虫不可语冰”。博客园有些人压根没看完你的文章&#xff0c;带着已有认知断章取义不暇思索上来就是喷。不过&#xff0c;以前也遇到过&#xff0c;现在也慢慢习惯了。对于托管堆内存泄漏的说法&#xff0c;不管认不认同&#xff0c;我还是希…

机器学习之数据预处理——归一化,标准化

机器学习之数据预处理——归一化,标准化 基础知识1.什么是特征预处理2.预处理方法 :3.预处理API:数据的标准化(normalization)和归一化数据的标准化数据归一化1 把数变为(0,1)之间的小数2 把有量纲表达式变为无量纲表达式常用归一化方法最大-最小标准化(MinMaxScaler)Z-s…

css less 不要作用到子对象_使用Less实现网站主题切换

v-easy-components change theme很多初学前端的开发同学一定有一种想法&#xff0c;就是如何更改网站的主题。前年&#xff08;2018&#xff09;&#xff0c;我也陷入了思考&#xff0c;如何切换网站主题呢&#xff1f;当时不知道less&#xff0c;只想到一种办法&#xff0c;就…

展望2021,Java、Go、.NET,谁主沉浮?

伴随着年底.NET社区活动&#xff0c;近日跟几位微软MVP大佬聊天请益&#xff0c;收获颇丰。程序员都有个话题避不开&#xff0c;就是各编程语言的优劣&#xff0c;大佬们的见识既有意思也有深度&#xff0c;这里为大家整理一下&#xff0c;其中Java、Golang和.NET是讨论焦点。J…

机器学习之数据集划分——训练集测试集划分,划分函数,估计器的使用

训练集测试集划分&#xff0c;划分函数&#xff0c;估计器的使用参考文章训练集、验证集和测试集的划分及交叉验证的讲解划分训练集和测试集的函数学习sklearn数据集&#xff0c;数据集划分&#xff0c;估计器详细讲解参考文章 训练集、验证集和测试集的划分及交叉验证的讲解 …

labuladong 的算法小抄_关于算法笔试的几个套路,一点就透

以下文章来源于labuladong &#xff0c;作者labuladong我知道各位是被标题吸引进来的&#xff0c;那就不废话&#xff0c;先说几个算法笔试的硬核套路&#xff0c;再说说语言选择和做题复习的策略。避实就虚大家也知道&#xff0c;大部分笔试题目都需要你自己来处理输入数据&am…