Nacos 与 Asp.net Core Api 整合初探

背景

现在比较流行微服务部署:方便快速迭代且不影响其他业务系统

nacos

之前想转java 然后关注了一下java 方面的技术,后面接触了nacos 所以就用nacos 来作为服务注册和配置中心

接下来让我们开始吧

安装nacos

请参考这里:教程

开始编码

创建2 个 webapi 项目,一个类库项目

 

 在 GR.Nacos 中添加引用

1   <ItemGroup>
2     <PackageReference Include="Microsoft.Extensions.Http.Polly" Version="7.0.0" />
3     <PackageReference Include="nacos-sdk-csharp" Version="1.3.4" />
4     <PackageReference Include="nacos-sdk-csharp.AspNetCore" Version="1.3.4" />
5     <PackageReference Include="nacos-sdk-csharp.Extensions.Configuration" Version="1.3.4" />
6   </ItemGroup>

 

编写扩展

 1 using Microsoft.Extensions.Configuration;
 2 using Microsoft.Extensions.DependencyInjection;
 3 using Nacos.AspNetCore.V2;
 4 using Polly;
 5 using System;
 6 
 7 namespace GR.Nacos
 8 {
 9     /// <summary>
10     /// 扩展
11     /// </summary>
12     public static class NacosExtension
13     {
14         /*
15          * https://github.com/nacos-group/nacos-sdk-csharp
16          * https://www.cnblogs.com/hangmei/p/16191160.html
17          1、必须要有 ConfigUseRpc和NamingUseRpc这2个参数,若用的是http协议,则都是false ,若用grpc协议则为true.(这个官方提供的demo没有写,就会报错)
18 
19          2、Listeners 对应配置文件。DataId是配置名称,Tenant是命名空间名称。Group组名。
20 
21          3、ServerAddresses是Nacos的服务器地址,可以添加多个。
22 
23          4、创建新的命名空间,则 Namespace对应的是命名空间的Id 。
24 
25          5、Listeners里添加的配置文件一定要存在,不要有多余的节点,可以少,但是不可以多。Group也不能填错。
26          */
27         public static IConfigurationBuilder AddNacos(this IConfigurationBuilder builder, IServiceCollection services)
28         {
29             var config = builder.Build();
30             // 默认会使用JSON解析器来解析存在Nacos Server的配置
31             builder.AddNacosV2Configuration(config.GetSection("NacosConfig"));
32             //
33             services.AddNacos();
34             return builder;
35         }
36 
37         public static IServiceCollection AddNacos(this IServiceCollection services, IConfiguration Configuration)
38         {
39             services.AddNacosAspNet(Configuration, "NacosConfig")
40                     .AddNacos();
41             return services;
42         }
43 
44 
45         private static IServiceCollection AddNacos(this IServiceCollection services)
46         {
47             services.AddHttpClient(NacosConst.HttpClientName, client =>
48             {
49                 //添加自定义头
50                 //client.DefaultRequestHeaders.Add("client-name", "xx");
51 
52                 //增加授权
53                 //client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Beaer", "xxx");
54             });
55             //https://zhuanlan.zhihu.com/p/381738224
56             services.AddHttpClient(NacosConst.HttpClientNamePolly, client =>
57             {
58                 //添加自定义头
59                 //client.DefaultRequestHeaders.Add("client-name", "xx");
60 
61                 //增加授权
62                 //client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Beaer", "xxx");
63             })
64               //请求失败时指定polly策略,这里指定的是间隔重试策略
65              .AddTransientHttpErrorPolicy(c => c.WaitAndRetryAsync(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(4) }));
66            
67             services.AddScoped<INacosProxyService, NacosProxyService>();
68             return services;
69         }
70 
71         //public static IApplicationBuilder UseNacos(this IApplicationBuilder app)
72         //{ 
73 
74         //}
75     }
76 }

编写代理服务

  1 using Microsoft.Extensions.Configuration;
  2 using Microsoft.Extensions.Options;
  3 using Nacos.AspNetCore.V2;
  4 using Nacos.V2;
  5 using System.Net;
  6 using System.Net.Http;
  7 using System.Threading.Tasks;
  8 
  9 namespace GR.Nacos
 10 {
 11     public class NacosProxyService : INacosProxyService
 12     {
 13         /// <summary>
 14         /// httpClient
 15         /// </summary>
 16         private readonly IHttpClientFactory _httpClient;
 17         /// <summary>
 18         /// 发现服务
 19         /// </summary>
 20         private readonly INacosNamingService _nacosNamingService;
 21         /// <summary>
 22         /// 配置
 23         /// </summary>
 24         private readonly NacosAspNetOptions _nacosOption;
 25 
 26         /// <summary>
 27         /// 构造函数
 28         /// </summary>
 29         /// <param name="httpClient"></param>
 30         /// <param name="nacosNamingService"></param>
 31         public NacosProxyService(IHttpClientFactory httpClient
 32             , INacosNamingService nacosNamingService,
 33             IOptions<NacosAspNetOptions> nacosOption)
 34         {
 35             _httpClient = httpClient;
 36             _nacosNamingService = nacosNamingService;
 37             _nacosOption = nacosOption.Value;
 38         }
 39 
 40         /// <summary>
 41         /// POST 请求
 42         /// </summary>
 43         /// <param name="serviceName"></param>
 44         /// <param name="relativeUrl"></param>
 45         /// <param name="isRetryPolly"></param>
 46         public async Task<HttpResponseMessage> PostAsync(string serviceName, string relativeUrl, HttpContent content, bool isRetryPolly = true)
 47         {
 48             var url = await this.AssembleUrl(serviceName, relativeUrl);
 49             if (string.IsNullOrWhiteSpace(url))
 50             {
 51                 return new HttpResponseMessage(HttpStatusCode.NotFound);
 52             }
 53             var client = this.CreateHttpClient(isRetryPolly);
 54             return await client.PatchAsync(url, content);
 55         }
 56 
 57         /// <summary>
 58         /// GET 请求
 59         /// </summary>
 60         /// <param name="serviceName"></param>
 61         /// <param name="relativeUrl"></param>
 62         /// <param name="isRetryPolly"></param>
 63         public async Task<HttpResponseMessage> GetAsync(string serviceName, string relativeUrl, bool isRetryPolly = true)
 64         {
 65             var url = await this.AssembleUrl(serviceName, relativeUrl);
 66             if (string.IsNullOrWhiteSpace(url))
 67             {
 68                 return new HttpResponseMessage(HttpStatusCode.NotFound);
 69             }
 70             var client = this.CreateHttpClient(isRetryPolly);
 71             return await client.GetAsync(url);
 72         }
 73          
 74         /// <summary>
 75         /// 创建 HttpClient
 76         /// </summary>
 77         /// <param name="isRetryPolly"></param>
 78         /// <returns></returns>
 79         private HttpClient CreateHttpClient(bool isRetryPolly = true)
 80         {
 81             return _httpClient.CreateClient(isRetryPolly ? NacosConst.HttpClientNamePolly : NacosConst.HttpClientName);
 82         }
 83 
 84 
 85         /// <summary>
 86         /// 组装URL
 87         /// </summary>
 88         /// <param name="serviceName"></param>
 89         /// <param name="relativeUrl"></param>
 90         private async Task<string> AssembleUrl(string serviceName, string relativeUrl)
 91         {
 92             var instance = await _nacosNamingService.SelectOneHealthyInstance(serviceName, _nacosOption.GroupName);
 93             var host = string.Format("{0}:{1}", instance.Ip, instance.Port);
 94             var http = instance.Metadata.TryGetValue("secure", out _) ? "https" : "http";
 95             //都是走配置文件
 96             //var http = _nacosOption.Secure ? "https" : "http";
 97             if (string.IsNullOrWhiteSpace(http) || string.IsNullOrWhiteSpace(host))
 98             {
 99                 return "";
100             }
101             return string.Format("{0}://{1}/{2}", http, host, relativeUrl);
102         }
103     }
104 }

两个api 项目都引用这个类库

添加 appsettings 配置文件,注意 urls 配置节点不能少,因为需要设置端口号,不然别的程序通过你认为的api 端口来调用你这个应用,会找不到服务,会提示目标服务器积极拒绝

 

 

 

 调用例子

 

 

 

posted @ 2022-11-25 16:58  细品人生  阅读(229)  评论(0编辑  收藏  举报