.net consul 封装 演变(二)
上一篇重复造轮子 这一篇 进行封装

ConfigOptions 文件夹 中的代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsulCustomExtend.ConfigOptions
{
public class ConsulSettings
{
public ConsulUI ConsulUI { get; set; }
public ConsulSevice ConsulSevice { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsulCustomExtend.ConfigOptions
{
/// <summary>
/// 注册服务
/// </summary>
public class ConsulSevice
{
/// <summary>
/// 服务id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 服务地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// 服务名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 标签
/// </summary>
public string[] Tags { get; set; }
/// <summary>
/// 端口号
/// </summary>
public int Port { get; set; }
public ConsulHealthCheck HealthCheck { get; set; }
}
/// <summary>
/// 健康检查
/// </summary>
public class ConsulHealthCheck
{
/// <summary>
/// 健康检查地址
/// </summary>
public string HTTP { get; set; }
/// <summary>
/// 每隔几秒 进行健康检查
/// </summary>
public int Interval { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsulCustomExtend.ConfigOptions
{
/// <summary>
/// ConsulUI
/// </summary>
public class ConsulUI
{
/// <summary>
/// UI 地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// 数据中心
/// </summary>
public string Datacenter { get; set; }
}
}
ConsulExtend 文件夹中的代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Consul;
using ConsulCustomExtend.ConfigOptions;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace ConsulCustomExtend.ConsulExtend
{
public static class ConsulExtend
{
public static IServiceCollection AddConsul(this IServiceCollection services, IConfiguration config)
{
services.Configure<ConsulSettings>(config.GetSection("ConsulSettings"));
services.AddScoped<ConsulClient>(sp =>
{
IOptionsSnapshot<ConsulSettings> options = sp.GetRequiredService<IOptionsSnapshot<ConsulSettings>>();
ConsulSettings settings = options.Value;
return new ConsulClient(config =>
{
string addr = settings.ConsulUI.Address;
string datacenter = settings.ConsulUI.Datacenter;
config.Address = new Uri(addr);
config.Datacenter = datacenter;
});
});
services.AddScoped<IConsulCustom, ConsulCustom>();
return services;
}
public async static Task<IApplicationBuilder> UseConsul(this IApplicationBuilder app)
{
using var scope = app.ApplicationServices.CreateScope();
ConsulSettings consulSettings = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<ConsulSettings>>().Value;
using ConsulClient client = new ConsulClient(config =>
{
string addr = consulSettings.ConsulUI.Address;
string datacenter = consulSettings.ConsulUI.Datacenter;
config.Address = new Uri(addr);
config.Datacenter = datacenter;
});
var registration = new AgentServiceRegistration
{
ID = Guid.NewGuid().ToString(),
Address = consulSettings.ConsulSevice.Address,
Name = consulSettings.ConsulSevice.Name,
Tags = consulSettings.ConsulSevice.Tags,
Port = consulSettings.ConsulSevice.Port,
Check = new AgentServiceCheck
{
HTTP = consulSettings.ConsulSevice.HealthCheck.HTTP, // "http://192.168.0.198:7777/health",///健康检查地址
Interval = TimeSpan.FromSeconds(consulSettings.ConsulSevice.HealthCheck.Interval)
}
};
await client.Agent.ServiceRegister(registration);
return app;
}
}
}
根目录下代码
using Consul;
using ConsulCustomExtend.ConfigOptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsulCustomExtend
{
public class ConsulCustom : IConsulCustom
{
private readonly ConsulClient consulClient;
public ConsulCustom(ConsulClient consulClient)
{
this.consulClient = consulClient;
}
/// <summary>
/// 获取所有服务
/// </summary>
/// <returns></returns>
public async Task<ServiceNode[]> GetServicesAllAsync()
{
var queryRuslt = await consulClient.Agent.Services();
AgentService[] agentServices = queryRuslt.Response.Values.ToArray();
ServiceNode[] serviceNodes = agentServices.Select(item => new ServiceNode
{
Address = item.Address,
ID = item.ID,
Port = item.Port,
Name = item.Service,
Tags = item.Tags
}).ToArray();
return serviceNodes;
}
public async Task<int> ReloadAsync()
{
string nodeName = consulClient.Agent.NodeName;
WriteResult writeResult = await consulClient.Agent.Reload(nodeName);
return (int)writeResult.StatusCode;
}
public async Task ServiceDeregisterAllAsync()
{
QueryResult<Dictionary<string, AgentService>> queryResult = await consulClient.Agent.Services();
AgentService[] agentServices = queryResult.Response.Values.ToArray();
foreach (var item in agentServices)
{
string serivceId = item.ID;
await consulClient.Agent.ServiceDeregister(serivceId);
}
}
public async Task<int> ServiceDeregisterAsync(string id)
{
WriteResult writeResult = await consulClient.Agent.ServiceDeregister(id);
return (int)writeResult.StatusCode;
}
public async Task<int> ServiceRegisterAsync(ConsulSevice consulSevice)
{
var registration = new AgentServiceRegistration
{
ID = consulSevice.Id,
Address = consulSevice.Address,// "192.168.0.198",
Name = consulSevice.Name, //"consultest",
Tags = consulSevice.Tags, //new[] { "consultest" },
Port = consulSevice.Port,// 7777,
Check = new AgentServiceCheck
{
HTTP = consulSevice.HealthCheck.HTTP,// "http://192.168.0.198:7777/health",///健康检查地址
Interval = TimeSpan.FromSeconds(consulSevice.HealthCheck.Interval)// TimeSpan.FromSeconds(3)
}
};
WriteResult writeResult = await this.consulClient.Agent.ServiceRegister(registration);
return (int)writeResult.StatusCode;
}
public void Dispose()
{
if (consulClient != null)
{
consulClient.Dispose();
GC.SuppressFinalize(this);
}
}
}
}
using ConsulCustomExtend.ConfigOptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsulCustomExtend
{
public interface IConsulCustom:IDisposable
{
/// <summary>
/// 获取所有服务
/// </summary>
Task<ServiceNode[]> GetServicesAllAsync();
/// <summary>
/// 注销所有服务
/// </summary>
Task ServiceDeregisterAllAsync();
/// <summary>
/// 注销服务id
/// </summary>
/// <param name="id">服务id</param>
/// <returns>注销返回状态码 200成功</returns>
Task<int> ServiceDeregisterAsync(string id);
/// <summary>
/// 重新加载
/// </summary>
/// <returns>重新加载返回状态码 200成功</returns>
Task<int> ReloadAsync();
/// <summary>
/// 服务注册
/// </summary>
/// <param name="consulSevice"></param>
/// <returns>注册状态StatusCode</returns>
Task<int> ServiceRegisterAsync(ConsulSevice consulSevice);
}
}
using ConsulCustomExtend.ConfigOptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsulCustomExtend
{
public interface IConsulCustom:IDisposable
{
/// <summary>
/// 获取所有服务
/// </summary>
Task<ServiceNode[]> GetServicesAllAsync();
/// <summary>
/// 注销所有服务
/// </summary>
Task ServiceDeregisterAllAsync();
/// <summary>
/// 注销服务id
/// </summary>
/// <param name="id">服务id</param>
/// <returns>注销返回状态码 200成功</returns>
Task<int> ServiceDeregisterAsync(string id);
/// <summary>
/// 重新加载
/// </summary>
/// <returns>重新加载返回状态码 200成功</returns>
Task<int> ReloadAsync();
/// <summary>
/// 服务注册
/// </summary>
/// <param name="consulSevice"></param>
/// <returns>注册状态StatusCode</returns>
Task<int> ServiceRegisterAsync(ConsulSevice consulSevice);
}
}
测试 ConsulWebAPI
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
//"AllowedHosts": "*",
//"consul": {
// "address": "http://192.168.0.168:8500",
// "datacenter": "dc1"
//},
"ConsulSettings": {
"ConsulUI": {
"Address": "http://192.168.0.168:8500",
"Datacenter": "dc1"
},
"ConsulSevice": {
"Address": "192.168.0.198",
"Name": "TS1",
"Tags": ["userconsul"],
"Port": 7777,
"HealthCheck": {
"HTTP": "http://192.168.0.198:7777/health",
"Interval": 5
}
}
}
}
using ConsulCustomExtend;
using Microsoft.AspNetCore.Mvc;
using ConsulCustom = ConsulCustomExtend.ConfigOptions;
namespace ConsulWebAPI.Controllers
{
/// <summary>
/// 测试封装Consul
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class TestConsulController : ControllerBase
{
private readonly IConsulCustom consulCustom;
public TestConsulController(IConsulCustom consulCustom)
{
this.consulCustom = consulCustom;
}
/// <summary>
/// 获取 所有服务
/// </summary>
/// <returns></returns>
[HttpGet("GetServicesAll")]
public async Task<ActionResult> GetServicesAll()
{
ServiceNode[] serviceNodes = await this.consulCustom.GetServicesAllAsync();
return Ok(serviceNodes);
}
/// <summary>
/// 注销所有
/// </summary>
/// <returns></returns>
[HttpGet("ServiceDeregister")]
public async Task<ActionResult> ServiceDeregister()
{
await this.consulCustom.ServiceDeregisterAllAsync();
return Ok();
}
/// <summary>
/// 节点 刷新
/// </summary>
/// <returns></returns>
[HttpGet("Reload")]
public async Task<ActionResult> Reload()
{
int statusCode = await this.consulCustom.ReloadAsync();
return Ok(statusCode);
}
/// <summary>
/// 通过id服务注销
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("ServiceDeregister/{id}")]
public async Task<ActionResult> ServiceDeregister([FromRoute] string id)
{
int statusCode = await this.consulCustom.ServiceDeregisterAsync(id);
return Ok(statusCode);
}
/// <summary>
/// 服务注册
/// </summary>
/// <returns></returns>
[HttpPost("ServiceRegister")]
public async Task<ActionResult> ServiceRegister( ConsulCustomExtend.ConfigOptions.ConsulSevice consulSevice)
{
int statusCode = await this.consulCustom.ServiceRegisterAsync(consulSevice);
return Ok(statusCode);
}
}
}
using Consul;
using ConsulCustomExtend.ConsulExtend;
using Microsoft.Extensions.Options;
using System;
using System.Net;
using System.Reflection;
using System.Runtime.Intrinsics;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Title = "consul测试",
Description = "consul测试",
Version = "v1",
});
string xmlPath = Assembly.GetExecutingAssembly().GetName().Name+".xml";
string pathStr = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, xmlPath);
options.IncludeXmlComments(pathStr, true);
});
//注入 consul 扩展
builder.Services.AddConsul(builder.Configuration);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json ","v1");
});
}
app.Map("/health", async next =>
{
next.Response.StatusCode = (int)HttpStatusCode.OK;
app.Logger.LogError($"{next.Request.Host}consul健康检查成功");
await next.Response.WriteAsync("200");
});
//注册
//UseCustomConsulAsync();
//使用Consul注入
await app.UseConsul();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
async void UseCustomConsulAsync()
{
using ConsulClient client = new ConsulClient(config =>
{
string addr = app.Configuration["consul:address"];
string datacenter = app.Configuration["consul:datacenter"];
config.Address = new Uri(addr);
config.Datacenter = datacenter;
});
var registration = new AgentServiceRegistration
{
ID = Guid.NewGuid().ToString(),
Address = "192.168.0.198",
Name = "consultest",
Tags = new[] { "consultest" },
Port = 7777,
Check = new AgentServiceCheck
{
HTTP = "http://192.168.0.198:7777/health",///健康检查地址
Interval = TimeSpan.FromSeconds(3)
}
};
await client.Agent.ServiceRegister(registration);
}
测试


最后 总结 封装的还是很顺利 Consul 主要是通过 Agent 进行 注册 ,和健康检查 这 从代码 上也能 体现出来
另外 app.ApplicationServices.GetRequiredService 是获取根容器上的 注入实例 单例模式是的实例是在根容器上 因为我注入的 是scope模式 所以 这样获取 会报错
要 创建 createscope 来获取 实例 这里 是一个技术点

浙公网安备 33010602011771号