.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…

容器的那点事

当我们的后端服务器不够用的时候&#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;以及历史迭代之…

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

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

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

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

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…

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

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

TVP两周年:携手同行,让未来可见

TVP两周年2018年12月15日&#xff0c;在北京的腾讯云社区开发者大会上&#xff0c;作为腾讯云构建开发者生态的重要战略&#xff0c;TVP计划正式发布。2020年12月15日&#xff0c;不知不觉&#xff0c;腾讯云TVP已经走过了两度春秋。从0到1的探索&#xff0c;1到10的成长&#…

加密封装 怎么把_不要再封装各种Util工具类了,这个神级框架值得拥有!

Hutool 谐音 “糊涂”&#xff0c;寓意追求 “万事都作糊涂观&#xff0c;无所谓失&#xff0c;无所谓得” 的境界。Hutool 是一个 Java 工具包&#xff0c;也只是一个工具包&#xff0c;它帮助我们简化每一行代码&#xff0c;减少每一个方法&#xff0c;让 Java 语言也可以 “…

Oh my God, Swagger API文档竟然可以这样写?

最好的总会在不经意间出现。“作为后端程序员&#xff0c;免不了与前端同事对接API&#xff0c; 一个书写良好的API设计文档可有效提高与前端对接的效率。为避免联调时来回撕逼&#xff0c;今天我们聊一聊正确编写Swaager API文档的姿势。基础Swagger用法在ConfigureServices配…

vue 前端设置允许跨域_web 前端的一些小问题

关于vue使用axios post发送json数据跨域请求403的解决方法&#xff1a;1. 问题vue开发的时候&#xff0c;使用axios跨域发送请求&#xff0c;同时post发送的数据格式是json格式&#xff0c;发送出去的时候发现控制台报错403&#xff0c;返回的信息提示是跨域的问题&#xff0c;…

如何在 Windows 10 上安装 WSL 2

翻译自 Joey Sneddon 2020年10月30日的文章《How to Install WSL 2 on Windows 10》 [1]如果您想在最新的 Windows 版本中尝试经过改进的 Windows 子系统 Linux 2 (即 WSL 2) [2]&#xff0c;要怎么做呢&#xff1f;我们在本文中介绍了安装它所需要做的所有事情。WSL 2 是微软早…

lnmp无法远程连接mysql_MySQL(一):设置root 可以远程连接MySQL

在mysql在远程主机或虚拟机上时&#xff0c;远程连接mysql数据库一般都使用GUI工具&#xff0c;比如Mac下的Sequel Pro&#xff1b;win和linux下的Sqlyog&#xff1b; 还有大名鼎鼎的Navicat。有人也许会说命令行多好&#xff0c;对着黑黑的屏幕噼里啪啦的一顿敲&#xff0c;屏…

云付认证已通过可以支付吗_海科融通丨刷新支付日常问题【附交易操作步奏】...

01常见问题汇总QPIN秘钥检验出错A&#xff1a;认证时不要频繁点击&#xff0c;点完后等一等系统反应&#xff0c;可联系客服处理。Q报错99&#xff0c;该小商户已入网A&#xff1a;提供商户编号给服务经理处理。Q终端屏幕无法签字A&#xff1a;待机界面&#xff0c;输入#0#&…

邀请函|WorkShop报名通道开启,来就送礼!

作为互联网行业的年度盛会今年除延续以往的开幕与论坛技术分享外还增设了Work Shop 体验课程&#xff01;参加此次工作坊不仅能近距离和大佬进行互动体验项目开发的快感还能领取大会纪念卫衣、书籍等惊喜好礼是不是很期待&#xff1f;&#xff08;数量有限先到场先得&#xff0…

对象数组参数_【JavaScript 教程】标准库—Array 对象

作者 | 阮一峰1、构造函数Array是 JavaScript 的原生对象&#xff0c;同时也是一个构造函数&#xff0c;可以用它生成新的数组。var arr new Array(2);arr.length // 2arr // [ empty x 2 ]上面代码中&#xff0c;Array构造函数的参数2&#xff0c;表示生成一个两个成员的数组…

机器学习之无监督学习——聚类

机器学习之无监督学习——聚类无监督学习一、基于划分的聚类方法1、基于划分的方法 简介A、概念B、分组C、分组与样本 对应关系D、硬聚类 与 软聚类二、基于层次的聚类方法1、基于层次的聚类方法 概念 :2、基于层次的聚类方法 :A、聚合层次聚类 ( 叶子节点到根节点 )聚合层次聚…