引用地址:聊一聊如何在.NET Core中使用Nacos 2.0_dotNET跨平台
前言
随着 nacos 2.0.0 正式发布,老黄这边也跟着发布了 1.0.2 版本的 nacos-sdk-csharp。
下面简单聊一下相关的使用。
纯 SDK 的使用
首先要安装 nuget 包
<PackageReference Include="nacos-sdk-csharp" Version="1.0.2" />
这里有一点要注意,包名里面的 unofficial 已经移除,请确保使用对了正确的包。
下面就是依赖注入的配置。
-
services.AddNacosV2Config(x =>
-
{
-
x.ServerAddresses = new System.Collections.Generic.List<string> { "http://localhost:8848/" };
-
x.EndPoint = "";
-
x.Namespace = "cs-test";
-
/*x.UserName = "nacos";
-
x.Password = "nacos";*/
-
// swich to use http or rpc
-
x.ConfigUseRpc = true;
-
});
-
services.AddNacosV2Naming(x =>
-
{
-
x.ServerAddresses = new System.Collections.Generic.List<string> { "http://localhost:8848/" };
-
x.EndPoint = "";
-
x.Namespace = "cs-test";
-
/*x.UserName = "nacos";
-
x.Password = "nacos";*/
-
// swich to use http or rpc
-
x.NamingUseRpc = true;
-
});
其中有两个关键配置, ConfigUseRpc 和 NamingUseRpc,分别表示配置和服务是否要使用最新的 gRPC 协议和服务端对接。
服务端是 2.0.0 的,一定要设置成 true。
接下来看看配置这一块的使用。
配置这边暴露出来的接口是 INacosConfigService
。
发布,获取,删除配置的操作示例如下:
-
static async Task PublishConfig(INacosConfigService svc)
-
{
-
var dataId = "demo-dateid";
-
var group = "demo-group";
-
var val = "test-value-" + DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
-
await Task.Delay(500);
-
var flag = await svc.PublishConfig(dataId, group, val);
-
Console.WriteLine($"======================发布配置结果,{flag}");
-
}
-
static async Task GetConfig(INacosConfigService svc)
-
{
-
var dataId = "demo-dateid";
-
var group = "demo-group";
-
await Task.Delay(500);
-
var config = await svc.GetConfig(dataId, group, 5000L);
-
Console.WriteLine($"======================获取配置结果,{config}");
-
}
-
static async Task RemoveConfig(INacosConfigService svc)
-
{
-
var dataId = "demo-dateid";
-
var group = "demo-group";
-
await Task.Delay(500);
-
var flag = await svc.RemoveConfig(dataId, group);
-
Console.WriteLine($"=====================删除配置结果,{flag}");
-
}
这三个是常规操作,不会有太大的变化。
配置监听这一块是有所调整的,Listener 变成是必须要实现 IListener
接口的实例了。
其实里面也就只有一个方法,下面是一个简单的实现,收到配置变更信息后,把配置信息输出到控制台。
-
class DemoConfigListener : IListener
-
{
-
public void ReceiveConfigInfo(string configInfo)
-
{
-
Console.WriteLine($"================收到配置变更信息了 ===》{configInfo}");
-
}
-
}
有了监听的实现后,就可以添加和移除监听了。
-
static async Task ListenConfig(INacosConfigService svc, IListener listener)
-
{
-
var dataId = "demo-dateid";
-
var group = "demo-group";
-
// 添加监听
-
await svc.AddListener(dataId, group, listener);
-
await Task.Delay(500);
-
// 模拟配置变更,listener会收到变更信息
-
await PublishConfig(svc);
-
await Task.Delay(500);
-
await PublishConfig(svc);
-
await Task.Delay(500);
-
// 移除监听
-
await svc.RemoveListener(dataId, group, listener);
-
// 配置变更后,listener不会收到变更信息
-
await PublishConfig(svc);
-
}
把这些放在控制台里面跑一下
-
DemoConfigListener listener = new DemoConfigListener();
-
await PublishConfig(configSvc);
-
await GetConfig(configSvc);
-
await RemoveConfig(configSvc);
-
await ListenConfig(configSvc, listener);
大概能看到下面这样的输出:
再来看一下服务这一块的使用。
服务这边暴露出来的接口是 INacosNamingService
。
注册,获取,注销服务的操作示例如下:
-
static async Task RegisterInstance(INacosNamingService svc, int port = 9999)
-
{
-
await Task.Delay(500);
-
var instace = new Nacos.V2.Naming.Dtos.Instance
-
{
-
ServiceName = "demo-svc1",
-
ClusterName = Nacos.V2.Common.Constants.DEFAULT_CLUSTER_NAME,
-
Ip = "127.0.0.1",
-
Port = port,
-
Enabled = true,
-
Ephemeral = true,
-
Healthy = true,
-
Weight = 100,
-
InstanceId = $"demo-svc1-127.0.0.1-{port}",
-
Metadata = new System.Collections.Generic.Dictionary<string, string>
-
{
-
{ "m1", "v1" },
-
{ "m2", "v2" },
-
}
-
};
-
// 注册实例有很多重载,选适合自己的即可。
-
await svc.RegisterInstance(instace.ServiceName, Nacos.V2.Common.Constants.DEFAULT_GROUP, instace);
-
Console.WriteLine($"======================注册实例成功");
-
}
-
static async Task GetAllInstances(INacosNamingService svc)
-
{
-
await Task.Delay(500);
-
// 获取全部实例有很多重载,选适合自己的即可。最后一个参数表明要不要订阅这个服务
-
// SelectInstances, SelectOneHealthyInstance 是另外的方法可以获取服务信息。
-
var list = await svc.GetAllInstances("demo-svc1", Nacos.V2.Common.Constants.DEFAULT_GROUP, false);
-
Console.WriteLine($"======================获取实例成功,{Newtonsoft.Json.JsonConvert.SerializeObject(list)}");
-
}
-
static async Task DeregisterInstance(INacosNamingService svc)
-
{
-
await Task.Delay(500);
-
// 注销实例有很多重载,选适合自己的即可。
-
await svc.DeregisterInstance("demo-svc1", Nacos.V2.Common.Constants.DEFAULT_GROUP, "127.0.0.1", 9999);
-
Console.WriteLine($"======================注销实例成功");
-
}
这里的实例方法只是其中一部分,几乎每个方法都有很多的重载,大家按需选择即可。
服务的订阅,早期版本是一个印度小哥弄的一部分,基于udp的,不过效果并不好,所以一直没有启用这个功能。
在这个版本,已经启用了这个功能。
和监听配置一样,也要实现一个对应的接口 IEventListener
。
里面同样也就只有一个方法,下面是一个简单的实现,收到变更信息后,把服务信息输出到控制台。
-
class DemoEventListener : IEventListener
-
{
-
public Task OnEvent(IEvent @event)
-
{
-
if (@event is Nacos.V2.Naming.Event.InstancesChangeEvent e)
-
{
-
Console.WriteLine($"==========收到服务变更事件=======》{Newtonsoft.Json.JsonConvert.SerializeObject(e)}");
-
}
-
return Task.CompletedTask;
-
}
-
}
订阅的具体使用:
-
static async Task Subscribe(INacosNamingService svc, IEventListener listener)
-
{
-
// 订阅服务变化
-
await svc.Subscribe("demo-svc1", Nacos.V2.Common.Constants.DEFAULT_GROUP, listener);
-
// 模拟服务变化,listener会收到变更信息
-
await RegisterInstance(svc, 9997);
-
await Task.Delay(3000);
-
// 取消订阅
-
await svc.Unsubscribe("demo-svc1", Nacos.V2.Common.Constants.DEFAULT_GROUP, listener);
-
// 服务变化后,listener不会收到变更信息
-
await RegisterInstance(svc);
-
await Task.Delay(1000);
-
}
同样放到控制台看看效果。
-
DemoEventListener eventListener = new DemoEventListener();
-
await RegisterInstance(namingSvc);
-
await GetAllInstances(namingSvc);
-
await DeregisterInstance(namingSvc);
-
await Subscribe(namingSvc, eventListener);
大致输出如下:
到这里的话,纯 SDK 的基本使用就告一段落了。
下面再来看看集成 ASP.NET Core 的简单用法。
集成配置
集成配置,是为了集成 Microsoft.Extensions.Configuration
, 只需要变更 Provider 就可以替换配置源。
首先要安装 nuget 包
<PackageReference Include="nacos-sdk-csharp.Extensions.Configuration" Version="1.0.2" />
然后是相关配置
-
{
-
"NacosConfig": {
-
"Listeners": [
-
{
-
"Optional": false,
-
"DataId": "options1",
-
"Group": "DEFAULT_GROUP"
-
},
-
{
-
"Optional": false,
-
"DataId": "options2",
-
"Group": "DEFAULT_GROUP"
-
},
-
{
-
"Optional": false,
-
"DataId": "raw",
-
"Group": "DEFAULT_GROUP"
-
}
-
],
-
"Tenant": "cs",
-
"ServerAddresses": [ "http://localhost:8848/" ],
-
"UserName": "",
-
"Password": "",
-
"AccessKey": "",
-
"SecretKey": "",
-
"EndPoint": ""
-
}
-
}
这里的意思是,这个应用需要监听三个配置项的变化,分别是 options1,options2 和 raw。
Optional 设置成 false,表示这个配置项不是可选的,是必须的,少了它程序就会出错。
需要在 nacos 控制台添加对应的配置。
如果使用 Option 的方式来读取配置的话,还需要在 Startup 里面进行绑定。
-
public void ConfigureServices(IServiceCollection services)
-
{
-
services.Configure<Options1>(Configuration.GetSection("AppSettings:Options1"));
-
services.Configure<Options2>(Configuration.GetSection("AppSettings:Options2"));
-
services.AddControllers();
-
}
然后暴露出一个接口来查看配置。
-
[ApiController]
-
[Route("api/[controller]")]
-
public class ConfigController : ControllerBase
-
{
-
private readonly ILogger<ConfigController> _logger;
-
private readonly IConfiguration _configuration;
-
private readonly Options1 _settings1;
-
private readonly Options2 _settings2;
-
public ConfigController(
-
ILogger<ConfigController> logger,
-
IConfiguration configuration,
-
IOptionsMonitor<Options1> settings1,
-
IOptionsMonitor<Options2> settings2)
-
{
-
_logger = logger;
-
_configuration = configuration;
-
_settings1 = settings1.CurrentValue;
-
_settings2 = settings2.CurrentValue;
-
}
-
[HttpGet]
-
public string Get()
-
{
-
_logger.LogInformation($"=====Options1======{Newtonsoft.Json.JsonConvert.SerializeObject(_settings1)}======");
-
_logger.LogInformation($"=====Options2======{Newtonsoft.Json.JsonConvert.SerializeObject(_settings2)}======");
-
_logger.LogInformation($"=====Raw With ConnectionStr======{_configuration.GetConnectionString("Default")}======");
-
_logger.LogInformation($"=====Raw With Other======{_configuration["other"]}======");
-
return "ok";
-
}
-
}
初次访问,正常输出相应的配置信息。
在控制台修改部分信息后,再次访问,可以看到对应的配置信息已经更新了。
集成服务
集成服务,是为了方便程序启动时,自动把服务注册到 Nacos 里面。
首先要安装 nuget 包
<PackageReference Include="nacos-sdk-csharp.Extensions.AspNetCore" Version="1.0.2" />
然后是服务的相关配置。
-
"nacos": {
-
"EndPoint": "",
-
"ServerAddresses": [ "http://localhost:8848" ],
-
"DefaultTimeOut": 15000,
-
"Namespace": "cs",
-
"ListenInterval": 1000,
-
"ServiceName": "NetCoreNamingDemo",
-
"GroupName": "DEFAULT_GROUP",
-
"ClusterName": "DEFAULT",
-
"Ip": "",
-
"PreferredNetworks": "192.168",
-
"Port": 9877,
-
"Weight": 100,
-
"RegisterEnabled": true,
-
"InstanceEnabled": true,
-
"Ephemeral": true,
-
"Secure": false,
-
"AccessKey": "",
-
"SecretKey": "",
-
"UserName": "",
-
"Password": "",
-
"ConfigUseRpc": true,
-
"NamingUseRpc": true,
-
"NamingLoadCacheAtStart": "",
-
"Metadata": {
-
"aa": "bb",
-
"cc": "dd"
-
}
-
}
这里面多了几个配置要单独说明一下。
-
InstanceEnabled, 表示这个服务注册上去后,是否马上就上线
-
Secure,表示当前服务是否是安全实例,用于标识访问的时候是否要启用 https,这个在发现服务后,可以从 Metadata 里面取到
然后再 Startup 里面添加自动注册的代码。
-
public void ConfigureServices(IServiceCollection services)
-
{
-
services.AddNacosAspNet(Configuration);
-
services.AddControllers();
-
}
启动服务后,可以在 nacos 控制台看到相关的服务信息。
接下来就可以通过 INacosNamingService
接口来获取到这个服务了。
-
// 找出一个健康的实例
-
var instance = await _svc.SelectOneHealthyInstance("NetCoreNamingDemo", "DEFAULT_GROUP");
-
var host = $"{instance.Ip}:{instance.Port}";
-
// 根据 secure 来判断服务要不要用 https,
-
// 这里是约定,参考了 spring cloud 那边,不是强制的,也可以用其他标识
-
var baseUrl = instance.Metadata.TryGetValue("secure", out _)
-
? $"https://{host}"
-
: $"http://{host}";
-
if (string.IsNullOrWhiteSpace(baseUrl)) return "empty";
-
var url = $"{baseUrl}";
-
var client = _factory.CreateClient();
-
var resp = await client.GetAsync(url);
-
return await resp.Content.ReadAsStringAsync();
写在最后
本文虽然简单介绍了如何在 .NET Core 中使用 nacos 2.0 ,还有更多用法和细节等待挖掘和实现。
感兴趣的话,欢迎您的加入,一起开发完善。
nacos-sdk-csharp 的地址 :https://github.com/nacos-group/nacos-sdk-csharp
本文示例代码的地址 :https://github.com/catcherwong-archive/Nacos2Demo