1、ConsulConfig .cs
public class ConsulConfig
{
/// <summary>
/// Consul服務註冊地址
/// </summary>
public string ConsulAddress { get; set; }
/// <summary>
/// 當前服務名稱,可以多個實例共享
/// </summary>
public string ServiceName { get; set; }
/// <summary>
/// 當前服務地址[可選,如果Consul幫助類中能獲取到,這裏可以不配置]
/// </summary>
public string ServiceUriHost { get; set; }
/// <summary>
/// 當前服務端口號[可選,如果Consul幫助類中能獲取到,這裏可以不配置]
/// </summary>
public int ServiceUriPort { get; set; }
/// <summary>
/// 健康檢查的地址,當前服務公佈出來的一個api接口
/// </summary>
public string HealthCheck { get; set; }
}
2、ConsulConsumer.cs
public class ConsulConsumer:IServiceConsumer //定義成接口,以後換其它的註冊中心方便替換
{
private readonly string consulAddress;
public ConsulConsumer(IOptions<ConsulConfig> serviceOptions)
{
consulAddress = serviceOptions.Value.ConsulAddress;
}
public async Task<List<string>> 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<string>();
foreach (var item in result.Response)
{
list.Add($"{item.ServiceAddress}:{item.ServicePort}");
}
return list;
}
}
3、ConsulRegister .cs
/// <summary>
/// 服務註冊
/// </summary>
public static class ConsulRegister
{
public static IApplicationBuilder UseConsul(this IApplicationBuilder app)
{
//獲取服務配置項
var serviceOptions = app.ApplicationServices.GetRequiredService<IOptions<ConsulConfig>>().Value;
CheckConfig(serviceOptions);
Tuple<string, string, int> 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<IHostApplicationLifetime>();
//程序停止的時候取消註冊
lifetime.ApplicationStopping.Register(() =>
{
consulClient.Agent.ServiceDeregister(serviceId).Wait();
});
return app;
}
/// <summary>
/// 獲取當前主機的域名和端口
/// 用IIS啓動獲取不到。如果獲取不到必須保證配置文件配了
/// 啓動的時候指定--Urls纔可以獲取到;例如 :dotnet Service_One.dll --Urls "https://localhost:5002"
/// </summary>
/// <param name="serviceOptions"></param>
/// <param name="app"></param>
/// <returns>
/// 第一個返回值:健康檢查地址(例如:http://127.0.0.1:5001/healthcheck)
/// 第二個返回值:主機地址(例如:127.0.0.1)
/// 第三個返回值:端口號(例如:80)
/// </returns>
private static Tuple<string, string, int> GetHostInfo(ConsulConfig serviceOptions, IApplicationBuilder app)
{
#region
var features = app.Properties["server.Features"] as FeatureCollection;
var address = features.Get<IServerAddressesFeature>().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
}
/// <summary>
/// 檢查配置文件
/// </summary>
/// <param name="serviceOptions"></param>
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<ConsulConfig>(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<IServiceConsumer, ConsulConsumer>();
}
}
5、webapi項目的Startup.cs
//服務註冊者
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks(); //添加健康檢查,.net core自帶的
services.AddConsulRegister();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,IOptions<ConsulRegister> 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"