1、ConsulConfig .cs
public class ConsulConfig
{
///
/// Consul服务注册地址
///
public string ConsulAddress { get; set; }
///
/// 当前服务名称,可以多个实例共享
///
public string ServiceName { get; set; }
///
/// 当前服务地址[可选,如果Consul帮助类中能获取到,这里可以不配置]
///
public string ServiceUriHost { get; set; }
///
/// 当前服务端口号[可选,如果Consul帮助类中能获取到,这里可以不配置]
///
public int ServiceUriPort { get; set; }
///
/// 健康检查的地址,当前服务公布出来的一个api接口
///
public string HealthCheck { get; set; }
}
2、ConsulConsumer.cs
public class ConsulConsumer:IServiceConsumer //定义成接口,以后换其它的注册中心方便替换
{
private readonly string consulAddress;
public ConsulConsumer(IOptions serviceOptions)
{
consulAddress = serviceOptions.Value.ConsulAddress;
}
public async Task> GetServices(string serviceName)
{
var consulClient = new ConsulClient(configuration =>
{
//服务注册地址:集群中任意一个地址
configuration.Address = new Uri(consulAddress);
});
var result = await consulClient.Catalog.Service(serviceName);
if (result == null || result.Response == null || result.Response.Length < 1)
return null;
var list = new List();
foreach (var item in result.Response)
{
list.Add($"{item.ServiceAddress}:{item.ServicePort}");
}
return list;
}
}
3、ConsulRegister .cs
///
/// 服务注册
///
public static class ConsulRegister
{
public static IApplicationBuilder UseConsul(this IApplicationBuilder app)
{
//获取服务配置项
var serviceOptions = app.ApplicationServices.GetRequiredService>().Value;
CheckConfig(serviceOptions);
Tuple hostinfo = GetHostInfo(serviceOptions, app);
// 服务ID,唯一的
string serviceId = serviceOptions.ServiceName + Guid.NewGuid().ToString();
//节点服务注册对象
var registration = new AgentServiceRegistration()
{
ID = serviceId,
Name = serviceOptions.ServiceName, //对服务分组
Address = hostinfo.Item2, //服务地址
Port = hostinfo.Item3,
Tags = new string[] { }, //标签信息,服务发现的时候可以获取到的,负载均衡策略扩展的
Check = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(7), //在7秒未连接上服务之后注销关键服务
Interval = TimeSpan.FromSeconds(2), //每个2秒发送一次心跳检测
Timeout = TimeSpan.FromSeconds(3), //连接超时时间
HTTP = hostinfo.Item1 // //心跳检测访问的接口地址,需要自己在项目中写好这个接口
}
};
var consulClient = new ConsulClient(configuration =>
{
//服务注册地址:集群中任意一个地址
configuration.Address = new Uri(serviceOptions.ConsulAddress);
});
//注册到consul
consulClient.Agent.ServiceRegister(registration).Wait();
//获取主机生命周期管理接口
var lifetime = app.ApplicationServices.GetRequiredService();
//程序停止的时候取消注册
lifetime.ApplicationStopping.Register(() =>
{
consulClient.Agent.ServiceDeregister(serviceId).Wait();
});
return app;
}
///
/// 获取当前主机的域名和端口
/// 用IIS启动获取不到。如果获取不到必须保证配置文件配了
/// 启动的时候指定--Urls才可以获取到;例如 :dotnet Service_One.dll --Urls "https://localhost:5002"
///
///
///
///
/// 第一个返回值:健康检查地址(例如:http://127.0.0.1:5001/healthcheck)
/// 第二个返回值:主机地址(例如:127.0.0.1)
/// 第三个返回值:端口号(例如:80)
///
private static Tuple GetHostInfo(ConsulConfig serviceOptions, IApplicationBuilder app)
{
#region
var features = app.Properties["server.Features"] as FeatureCollection;
var address = features.Get().Addresses.FirstOrDefault();
string http = null, host = null;
int port = 0;
if (!string.IsNullOrEmpty(address))
{
var uri = new Uri(address);// 协议头:uri.Sechema 主机:uri.Host 端口:uri.Port
http = address + serviceOptions.HealthCheck;
host = uri.Scheme + "://" + uri.Host;
port = uri.Port;
}
else
{
http = $"{serviceOptions.ServiceUriHost}:{serviceOptions.ServiceUriPort}{serviceOptions.HealthCheck}";
host = serviceOptions.ServiceUriHost;
port = serviceOptions.ServiceUriPort;
}
if (string.IsNullOrEmpty(host) || port < 1)
throw new Exception("Consul配置未能获取到主机信息,请在consulconfig.json文件中配置");
Console.WriteLine("健康检查地址:" + http);
return Tuple.Create(http, host, port);
#endregion
}
///
/// 检查配置文件
///
///
private static void CheckConfig(ConsulConfig serviceOptions)
{
if (serviceOptions == null)
throw new Exception("请正确配置consulconfig.json,其中包含ConsulAddress、ServiceName、HealthCheck");
if (string.IsNullOrEmpty(serviceOptions.ConsulAddress))
throw new Exception("请正确配置ConsulAddress");
if (string.IsNullOrEmpty(serviceOptions.ServiceName))
throw new Exception("请正确配置ServiceName");
if (string.IsNullOrEmpty(serviceOptions.HealthCheck))
throw new Exception("请正确配置HealthCheck");
}
}
4、ConsulServiceCollectionExtensions.cs
public static class ConsulServiceCollectionExtensions
{
public static void AddConsulRegister(this IServiceCollection service)
{
//读取服务配置文件
try
{
var config = new ConfigurationBuilder().AddJsonFile("consulconfig.json").Build(); //nuget: Microsoft.Extensions.Configuration.Json
service.Configure(config); // nuget: Microsoft.Extensions.Options.ConfigurationExtensions
}
catch
{
throw new Exception("请正确配置consulconfig.json");
}
}
public static void AddConsulConsumer(this IServiceCollection service)
{
//读取服务配置文件
service.AddConsulRegister(); // nuget: Microsoft.Extensions.Options.ConfigurationExtensions
service.AddSingleton();
}
}
5、webapi项目的Startup.cs
//服务注册者
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks(); //添加健康检查,.net core自带的
services.AddConsulRegister();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,IOptions serviceOptions)
{
//启用健康检查,.net core自带的
app.UseHealthChecks(serviceOptions.Value.HealthCheck);
app.UseConsul();
}
//服务消费者
//通过构造函数依赖注入“ConsulConsumer”使用就可以
public void ConfigureServices(IServiceCollection services)
{
services.AddConsulConsumer();
}
6、consulconfig.json
{
"ConsulAddress": "http://127.0.0.1:8500", //Consul服务注册地址,如果是消费者,则只需要配置这个字段,其它的无需配置
"ServiceName": "Serivce_One", //当前服务名称,可以多个实例共享
"ServiceUriHost": "https://localhost", //当前服务地址
"ServiceUriPort": "44323", //当前服务地址
"HealthCheck": "/api/health/check" //健康检查的地址,当前服务公布出来的一个api接口
}
5、开启两个Service_One服务
dotnet Service_One.dll --Urls "https://localhost:5001"
dotnet Service_One.dll --Urls "https://localhost:5002"