|
随着Aspire发布preview5的发布,Microsoft.Extensions.ServiceDiscovery随之更新,
服务注册发现这个属于老掉牙的话题解决什么问题就不赘述了,这里主要讲讲Microsoft.Extensions.ServiceDiscovery(preview5)以及如何扩展其他的中间件的发现集成 .
Microsoft.Extensions.ServiceDiscovery官方默认提供的Config,DNS,YARP三种Provider,使用也比较简单 :- builder.Services.AddServiceDiscovery();
- builder.Services.AddHttpClient<CatalogServiceClient>(static client =>
- {
- client.BaseAddress = new("http://todo");
- });
- builder.Services.ConfigureHttpClientDefaults(static http =>
- {
- // 全局对HttpClient启用服务发现
- http.UseServiceDiscovery();
- });
复制代码 然后 appsettings.json 为名为 todo 的服务配置终结点:- "Services": {
- "todo": {
- "http": [
- "http://localhost:5124"
- ]
- }
- }
复制代码 然后使用服务发现:- #region 模拟服务端的todo接口:
- var sampleTodos = new Todo[] {
- new(1, "Walk the dog"),
- new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)),
- new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))),
- new(4, "Clean the bathroom"),
- new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2)))
- };
- var todosApi = app.MapGroup("/todos");
- todosApi.MapGet("/", () => sampleTodos);
- todosApi.MapGet("/{id}", (int id) =>
- sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
- ? Results.Ok(todo)
- : Results.NotFound());
- #endregion
- public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplete = false);
- [JsonSerializable(typeof(Todo[]))]
- internal partial class AppJsonSerializerContext : JsonSerializerContext
- {
- }
- #region 测试服务发现和负载
- app.MapGet("/test", async (IHttpClientFactory clientFactory) =>
- {
- //这里服务发现将自动解析配置文件中的服务
- var client = clientFactory.CreateClient("todo");
- var response = await client.GetAsync("/todos");
- var todos = await response.Content.ReadAsStringAsync();
- return Results.Content(todos, contentType: "application/json");
- });
- #endregion
复制代码 运行程序后将会发现成功执行:
当然对于这样写死配置的服务发现一点都不灵活,因此应运而生了 YARP和DNS这些Provider, 目前服务注册发现使用Consul的还是挺多的,当然还有很多其他的轮子就不赘述了,这里我们来扩展一个Consul的服务发现Provider :
实现核心接口IServiceEndPointProvider- internal class ConsulServiceEndPointProvider(ServiceEndPointQuery query, IConsulClient consulClient, ILogger logger)
- : IServiceEndPointProvider, IHostNameFeature
- {
- const string Name = "Consul";
- private readonly string _serviceName = query.ServiceName;
- private readonly IConsulClient _consulClient = consulClient;
- private readonly ILogger _logger = logger;
- public string HostName => query.ServiceName;
- #pragma warning disable CA1816 // Dispose 方法应调用 SuppressFinalize
- public ValueTask DisposeAsync() => default;
- public async ValueTask PopulateAsync(IServiceEndPointBuilder endPoints, CancellationToken cancellationToken)
- {
- var flag = ServiceNameParts.TryParse(_serviceName, out var serviceNameParts);
- var sum = 0;
- if (flag)
- {
- var queryResult = await _consulClient.Health.Service(serviceNameParts.Host, string.Empty, true, cancellationToken);
- foreach (var serviceEntry in queryResult.Response)
- {
- var address = $"{serviceEntry.Service.Address}:{serviceEntry.Service.Port}";
- var isEndpoint = ServiceNameParts.TryCreateEndPoint(address, out var endPoint);
- if (isEndpoint)
- {
- ++sum;
- var serviceEndPoint = ServiceEndPoint.Create(endPoint!);
- serviceEndPoint.Features.Set<IServiceEndPointProvider>(this);
- serviceEndPoint.Features.Set<IHostNameFeature>(this);
- endPoints.EndPoints.Add(serviceEndPoint);
- _logger.LogInformation($"ConsulServiceEndPointProvider Found Service {_serviceName}:{address}");
- }
- }
- }
- if (sum == 0)
- {
- _logger.LogWarning($"No ConsulServiceEndPointProvider were found for service '{_serviceName}' ('{HostName}').");
- }
- }
- /// <inheritdoc/>
- public override string ToString() => Name;
- }
复制代码 实现 IServiceEndPointProviderFactory:- internal class ConsulServiceEndPointProviderFactory(IConsulClient consulClient, ILogger<ConsulServiceEndPointProviderFactory> logger) : IServiceEndPointProviderFactory
- {
- private readonly IConsulClient _consulClient = consulClient;
- private readonly ILogger<ConsulServiceEndPointProviderFactory> _logger = logger;
- public bool TryCreateProvider(ServiceEndPointQuery query, [NotNullWhen(true)] out IServiceEndPointProvider? resolver)
- {
- resolver = new ConsulServiceEndPointProvider(query, _consulClient, _logger);
- return true;
- }
- }
复制代码 接着扩展一下IServiceCollection- public static IServiceCollection AddConsulServiceEndpointProvider(this IServiceCollection services)
- {
- services.AddServiceDiscoveryCore();
- services.AddSingleton<IServiceEndPointProviderFactory, ConsulServiceEndPointProviderFactory>();
- return services;
- }
复制代码 最后添加一行代码 :- // 使用Microsoft.Extensions.ServiceDiscovery实现负载均衡
- builder.Services.AddServiceDiscovery()
- .AddConfigurationServiceEndPointResolver() //config
- .AddConsulServiceEndpointProvider(); //consul
复制代码 下面是Consul中注册完成的服务:
然后我们请求 ./test 调用服务,观察调试日志,成功了!
完整的代码:
https://github.com/vipwan/Biwen.Microsoft.Extensions.ServiceDiscovery.Consul
当然你也可以直接使用nuget引用 Biwen.Microsoft.Extensions.ServiceDiscovery.Consul 我已经发布到了nuget上 , 最后因为Aspire还在不停的迭代所以Biwen.Microsoft.Extensions.ServiceDiscovery.Consul后面还会存在一些变化, 前面的几个早期版本我都做了适配以最新的为准
来源:https://www.cnblogs.com/vipwan/p/18129361
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|